Java中的集合

Java中的集合
集合就像是一个购物车,可以将购买的所有商品的存放在一个统一的购物车中
集合的概念
-
现实生活: 很多的事物凑在一起
-
数学中的集合: 具有共同属性的事物的总体
-
Java中的集合类: 是一种工具类,是一种容器,里面可以存储任意数量的相同属性的类。
集合的作用
-
在类的内部对数据进行组织
-
简单快速的搜索大数量的条目
-
有的集合借口,提供了一系列排列有序的元素,并且可以在序列中快速地插入或者删除元素
-
有的集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这 个关键字可以是任意类型
两个集合框架
-
Collection
- List
- Queue
- Set
List、Queue、Set的区别:
List和Queue中的元素是有序排列的
Set中的元素是无序排列的
graph TD Collection(Collection) --> List(List) List(List) -.-> ArrayList[ArrayList] List(List) -.-> LinkedList[LinkedList] Collection(Collection) --> Queue(Queue) Queue(Queue)-.-> LinkedList[LinkedList] Collection(Collection) --> Set(Set) Set(Set) -.-> HashSet[HashSet] style ArrayList fill:#F4493F,color:#fff style HashSet fill:#F4493F,color:#fff style List fill:#00A9D4,color:#fff style Set fill:#00A9D4,color:#fff在Collection中存储的是一个一个独立的对象
-
Map
在Map中会以<Key,Value>,也就是两个对象形成一个映射的关系的方式去存储数据,这有点像C#中的Diectory类型。
Collection 接口、子接口及其实现类
List接口及其实现类 --- ArrayList
- List中的元素可以是重复的并且是有序排列的,被称为序列
- List可以精确的控制每个元素的插入位置,或删除某个位置元素
- ArrayList --- 数组序列,是List的一个重要实现类
- ArrayList的底层是由数组实现的
实现功能 --- 模拟学生选课功能
- 选择课程(往集合中添加课程)
- 删除所选的某门课程(删除集合中的元素)
- 查看所选课程
- 修改所选课程
//: Course.java
package com.faraj.collection;
public class Course {
public String name;
public String id;
public Course(String id, String name) {
this.id = id;
this.name = name;
}
}
创建课程类Course.java 由于是学习,类中的属性就用了public实际应用应该使用private修饰,然后添加getName; setName; getId; SetId方法;
//: Student.java
package com.faraj.collection;
import java.util.HashSet;
import java.util.Set;
public class Student {
public String id;
public String name;
public Set<Course> courses;
public Student(String id, String name){
this.id = id;
this.name = name;
this.courses = new HashSet<Course>();
}
}
创建学生类Student.java
//: ListTest.java
package com.faraj.collection;
import java.util.*;
public class ListTest {
public List<Course> coursesToSelect;
public ListTest() {
this.coursesToSelect = new ArrayList<Course>();
}
/**
* 给courseToSelect添加元素
*/
public void addTest() {
Course cr1 = new Course("1", "数据库系统概论");
coursesToSelect.add(cr1);
Course temp = coursesToSelect.get(0);
System.out.println("已添加课程: " + temp.id + "-" + temp.name);
coursesToSelect.add(0, new Course("2", "数据结构"));
Course temp2 = coursesToSelect.get(0);
System.out.println("已添加课程: " + temp2.id + "-" + temp2.name);
coursesToSelect.add(0, new Course("2", "数据结构"));
Course[] courses = new Course[]{
new Course("3", "线性代数"),
new Course("4", "ASP网页设计")
};
coursesToSelect.addAll(Arrays.asList(courses));
System.out.println("已添加课程: " + coursesToSelect.get(2).id + "-" +
coursesToSelect.get(2).name);
System.out.println("已添加课程: " + coursesToSelect.get(3).id + "-" +
coursesToSelect.get(3).name);
coursesToSelect.addAll(2, Arrays.asList(
new Course("5", "面向对象编程"),
new Course("6", "汇编语言")));
System.out.println("已添加课程: " + coursesToSelect.get(2).id + "-" +
coursesToSelect.get(2).name);
System.out.println("已添加课程: " + coursesToSelect.get(3).id + "-" +
coursesToSelect.get(3).name);
}
/**
* 获取集合中的所有元素
*/
public void getTest() {
for (int i = 0; i < coursesToSelect.size(); i++) {
System.out.println("课程:" + coursesToSelect.get(i).id + " - " +
coursesToSelect.get(i).name);
}
}
/**
* 通过迭代器遍历List
*/
public void iteratorTest() {
Iterator<Course> it = coursesToSelect.iterator();
int i = 1;
while (it.hasNext()) {
Course cr = it.next();
System.out.println("课程" + i++ + ":" + cr.id + "-" + cr.name);
}
}
/**
* 使用foreach方式循环获得list中的所有元素
*/
public void foreachTest() {
int i = 1;
for (Course cr : coursesToSelect) {
System.out.println("课程" + i++ + ":" + cr.id + "-" + cr.name);
}
}
/**
* 修改List中的元素
*/
public void modifyTest() {
coursesToSelect.set(1, new Course("7", "Java语言设计"));
}
/**
* 删除List中的元素
*/
public void removeTest(){
coursesToSelect.remove(0);
}
public static void main(String[] args) {
ListTest lt = new ListTest();
lt.addTest();
// lt.getTest();
// lt.iteratorTest();
lt.modifyTest();
lt.removeTest();
lt.foreachTest();
}
}
创建备选课程类ListTest.java
package com.faraj.collection;
import java.util.*;
public class SetTest {
public List<Course> coursesToSelect;
public SetTest() {
coursesToSelect = new ArrayList<Course>();
}
public void add() {
coursesToSelect.addAll(
Arrays.asList(
new Course("1", "数据库系统概论"),
new Course("2", "C语言基础"),
new Course("3", "Python语言实践"),
new Course("4", "基础算法实现"),
new Course("5", "汇编语言"),
new Course("6", "Linux基础"),
new Course("7", "面向对象编程"))
);
}
public void getAll() {
for (Course c : coursesToSelect) {
System.out.println(c.id + "--" + c.name);
}
}
public static void main(String[] args) {
SetTest st = new SetTest();
st.add();
st.getAll();
Student stu = new Student("1", "Faraj");
Scanner sca = new Scanner(System.in);
System.out.println("Welcome Stu. " + stu.name + "to select courses. You should and only can select 3 course.");
int num = 1;
for (int i = 0; i < 3; i++) {
System.out.println("Please choose NO. " + num + " course's ID");
num ++;
String input = sca.next();
for (Course cor : st.coursesToSelect) {
if (cor.id.equals(input)) {
stu.courses.add(cor);
}
}
}
System.out.println("你选择了:");
for (Course stuC : stu.courses) {
System.out.println(stuC.id + " - " + stuC.name);
}
}
}
Map和HashMap
Map接口
- Map提供了一种映射关系,其中的元素是以键值()对的形式存储的,能够实现根据key查找value
- Map中的键值对是以Entry类型的对象实例形式存在
- key不可重复,但是value值可以重复
- 每个key只能映射一个值
- Map 支持范性,Map<K,V>
HashMap类
- HashMap是Map的一个重要实现类,也是最常用的,基于哈希表实现
- HashMap中的Entry对象是无序排列的
- Key和Value的值都可以为null, 但是一个HashMap中只能有一个Key值为null的映射(Key值不可重复)
案例:
功能说明: 通过Map<String,Student>进行学生信息管理
其中key为学生的ID,value为学生对象
通过键盘输入学生信息
对集合中的学生信息进行增删改查
创建MapTest.java
//: MapTest.java
package com.faraj.collection;
import java.util.*;
public class MapTest {
public Map<String, Student> students;
public MapTest() {
students = new HashMap<>();
}
/**
* 通过put方法在Map中添加entry(键值对)
*/
public void putTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("请输入学生ID");
String id = scan.next();
int nextInput;
if (students.get(id) == null) {
System.out.println("请输入学生的姓名");
students.put(id, new Student(id, scan.next()));
System.out.println("是否继续添加? 1继续 2退出");
nextInput = scan.nextInt();
if (nextInput != 1) {
if (nextInput == 2) break;
}
} else {
System.out.println("该ID已存在");
System.out.println("是否重新添加 1是 2退出");
while (true) {
try {
nextInput = scan.nextInt();
break;
} catch (InputMismatchException e) {
System.out.println("你输入的内容不合法,请重新输入");
}
}
if (nextInput != 1) {
if (nextInput == 2) break;
}
}
}
}
/**
* 通过keySet取得遍历students
*/
public void keySetTest() {
Set<String> keys = students.keySet();
System.out.println("现已添加学生人数:" + keys.size());
for (String stuId : keys) {
System.out.println("学生(" + stuId + ")" + students.get(stuId).name);
}
}
/**
* 使用entrySet遍历students
*/
public void entrySetTest() {
Set<Map.Entry<String, Student>> entries = students.entrySet();
System.out.println("学生总数:" + entries.size());
for (Map.Entry<String, Student> entry : entries) {
System.out.println(entry.getKey() + " - " + entry.getValue().name);
}
}
/**
* 从Map中删除学生
*/
public void removeTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("请输入要删除的学生ID");
String id = scan.next();
if (students.get(id) == null) {
System.out.println("找不到该学生ID");
System.out.println("重新输入请输入1,退出应输入2");
int next = scan.nextInt();
if (next != 1) {
if (next == 2) {
break;
}
}
} else {
System.out.println("学生(" + id + ")" + students.get(id).name + " 已被删除");
students.remove(id);
System.out.println("重新输入请输入1,退出应输入2");
int next = scan.nextInt();
if (next != 1) {
if (next == 2) {
break;
}
}
}
}
}
/**
* 通过Put方法更改学生姓名
*/
public void modifyTest() {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.println("请输入要修改的学生的ID");
String stuId = scan.next();
Student stu = students.get(stuId);
if (stu == null) {
System.out.println("该ID的学生不存在,请重新输入");
continue;
}
System.out.println("当前学生(" + stuId + ")" + " - " + stu.name + ", 请输入修改后的名字");
String newName = scan.next();
Student newStu = new Student(stuId,newName);
students.put(stuId,newStu);
break;
}
}
public static void main(String[] args) {
MapTest mt = new MapTest();
mt.putTest();
mt.keySetTest();
mt.modifyTest();
mt.entrySetTest();
}
}
判断coursesToSelect(List)中是否存在课程
在Course.java中重写equals方法
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Course)){
return false;
}
Course cour = (Course)obj;
if (cour.name == null){
return this.name == null;
}else{
return this.name.equals(cour.name);
}
}
在SetTest.java类中添加以下方法
public void containsTest() {
System.out.println("请输入你要查找的名称");
Course inputCourse = new Course();
inputCourse.name = scan.next();
if (coursesToSelect.contains(inputCourse))
System.out.println("包含《" + inputCourse.name + "》");
else System.out.println("不包含《" + inputCourse.name + "》");
}
在SetTest.java的main方法中测试该方法
st.containsTest();
另外在List中还有一个containsAll()方法,其用法与contains差不多,就是传入的是一个比较的对象集合
判断Set中是否存在课程
将之前SetTest.java中的部分代码提取成一个单独的方法
public void createStuAndSelectCourse(){
Student stu = new Student("1", "Faraj");
System.out.println("Welcome Stu. " + stu.name + "to select courses. You should and only can select 3 course.");
int num = 1;
for (int i = 0; i < 3; i++) {
System.out.println("Please choose NO. " + num + " course's ID");
num++;
String input = scan.next();
for (Course cor : coursesToSelect) {
if (cor.id.equals(input)) {
stu.courses.add(cor);
}
}
}
System.out.println("你选择了:");
for (Course stuC : stu.courses) {
System.out.println(stuC.id + " - " + stuC.name);
}
}
在该文件中创建一下方法
public void setContainsTest() {
System.out.println("请输入学生选则的课程名称");
String name = scan.next();
Course inputCourse = new Course();
inputCourse.name = name;
if (student.courses.contains(inputCourse)) {
System.out.println("该学生选择了《" + inputCourse.name + "》");
} else {
System.out.println("该学生并没有选择《" + inputCourse.name + "》");
}
}
在main方法中调用新创建的两个方法
st.createStuAndSelectCourse();
st.setContainsTest();

运行程序发现HashSet中的contains方法告诉我们并没有包含课程
不用担心,这不是因为我们的代码写错了,而是……
HashSet的contains方法的实现机制
在Object这个根类中除了定义了上面通过Course类重写的equals()方法,还定义了一个hashCode()方法,这个方法返回的是对象的哈希码的值,当我们在调用HashSet的contains()方法的时候,其实先调用每个元素的hashCode获取它们的哈希码,如果哈希码相等的情况下,才会调用equals方法来判断是否相等,这有当这两个方法返回的值都是true的时候,contains()方法才会认定这个HashSet包含某个元素。
在Course类中添加hashCode方法的重写
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

然后重新启动程序,就能看到程序正常运行了
如何判断List中索引的位置
- 通过indexOf来获取某元素的索引位置
在之前的SetTest类中的containsTest方法中加入以下代码:
System.out.println("当前课程的索引位置为:"+coursesToSelect.indexOf(inputCourse));
public void containsTest() {
System.out.println("请输入你要查找的名称");
Course inputCourse = new Course();
inputCourse.name = scan.next();
if (coursesToSelect.contains(inputCourse)){
System.out.println("包含《" + inputCourse.name + "》");
System.out.println("当前课程的索引位置为:"+coursesToSelect.indexOf(inputCourse));
}
else System.out.println("不包含《" + inputCourse.name + "》");
indexOf方法会遍历整个集合,调用每个元素的equals方法,如果equals返回true则返回当前元素的索引位置,如果集合中有多个相同的对象,则会取第一个对应的元素的索引。
lastIndexOf方法会从集合中的最后一个元素开始遍历,判断的过程和indexOf是一样的
- 不管是lastIndexOf或者是indexOf如果未找到集合中包含的元素,都会返回-1
判断Map中是否包含指定的key或者value
可以调用.containsKey()方法来判断Map中是否包含key
调用.containsValue()方法来判断Map中是否包含value
注意⚠️:在使用.caontainsValue()方法的时候需要重写.equals()方法
在MapTest类中添加以下方法
public void containsKeyOrValue(){
System.out.println("请输入学生ID");
String id = scanner.next();
System.out.println("您输入的学生ID为:"+id+"该学生"+
(students.containsKey(id) ? "存在" : "不存在"));
if (students.containsKey(id)){
System.out.println("该学生的ID为:"+ id + "该学生的姓名为:" + students.get(id).name);
}
System.out.println("请输入学生姓名");
String name = scanner.next();
Student newStudent = new Student();
newStudent.name = name;
System.out.println("您输入的学生姓名为:" + name +
(students.containsValue(newStudent)? "该学生存在" : "该学生不存在"));
}
在Student类中重写equals方法
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student))
return false;
Student stu = (Student) obj;
if (stu.name == null) {
return this.name == null;
}else {
return this.name.equals(stu.name);
}
}
使用Collections.sort()方法排序
创建新类CollectionTest
package com.faraj.collection;
import java.util.*;
public class CollectionTest {
public Scanner scan;
public Random rand;
public CollectionTest() {
scan = new Scanner(System.in);
rand = new Random();
}
public void sortTest1() {
List<Integer> integers = new ArrayList<>();
for (int i = 0; i < 100; i++) {
integers.add(rand.nextInt(100));
}
System.out.println("=========Before sort=========");
for (Integer integer : integers) {
System.out.print(integer + " ");
}
Collections.sort(integers);
System.out.println();
System.out.println("=========After sort=========");
for (Integer integer : integers) {
System.out.print(integer + " ");
}
}
public static void main(String[] args) {
CollectionTest ct = new CollectionTest();
ct.sortTest1();
}
}
在上面的方法中,我们测试了对Integer 类型的排序,下面来测试一下String类型的sort()
public void sortTest2() {
List<String> strings = new ArrayList<>();
strings.add("Microsoft");
strings.add("Google");
strings.add("Apple");
System.out.println("=========Before sort=========");
for (String string : strings) {
System.out.print(string + "\t");
}
Collections.sort(strings);
System.out.println();
System.out.println("=========After sort=========");
for (String string : strings) {
System.out.print(string + "\t");
}
}
对于字符串,sort 的比较顺序
- 比较一个字符到最后一个字符
- 按照排序: 0~9、A~Z、a~z
public void sortTest3() {
String s = "qwertyuiopasdfghjklzxcvbnmZXCVBNMASDFGHJKLQWERTYUIOP1234567890";
List<String> strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
StringBuilder str = new StringBuilder();
for (int j = 0; j < 10; j++) {
int ra = rand.nextInt(62);
str.append(s.charAt(ra));
}
String newStr = str.toString();
if (!strings.contains(newStr)){
strings.add(newStr);
}
}
System.out.println("=========Before sort=========");
for (String string : strings)
System.out.println(string);
Collections.sort(strings);
System.out.println("=========After sort=========");
for (String string : strings)
System.out.println(string);
}
随机生成一个十位的字母大小写加数字的字符串,并进行排序
Comparable & Comparator
Comparable接口 —— 可比较的
- 实现该接口表示:这个类的实例是可以比较大小的,可以进行排序
- 定义了默认的比较规则
- 它的实现类必须实现compareTo()方法
- 当实现了Comparable接口的对象的实例进行比较的时候,就会调用对象中的compareTo()方法进行比较
- compareTo()方法返回正数表示大,负数表示小,0表示相等
Comparator接口 —— 比较工具接口
- 用于定义临时比较规则,而不是默认比较规则
- Comparator接口的实现类必须实现compare()方法
- Comparator和Comparable都是Java集合框架的成员
实现:
-
首先让Student类继承与Comparable接口
-
重写comparaTo方法
//: Student.java
package com.faraj.collection;
import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
import java.util.HashSet;
import java.util.Set;
public class Student implements Comparable<Student> {
public String id;
public String name;
public Set<Course> courses;
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Student))
return false;
Student stu = (Student) obj;
if (stu.name == null) {
return this.name == null;
}else {
return this.name.equals(stu.name);
}
}
public Student() {
}
public Student(String id, String name) {
this.id = id;
this.name = name;
this.courses = new HashSet<>();
}
@Override
public int compareTo(Student o) {
return Integer.compare(Integer.parseInt(this.id), Integer.parseInt(o.id));
}
}
- 创建StudentComparator类,让它继承与Comparator接口
- 重写compare方法
package com.faraj.collection;
import java.util.Comparator;
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
- 进行比较排序,在CollectionTest中添加以下方法
public void sortTest4() {
List<Integer> ints = new ArrayList<>();
do {
int count = rand.nextInt(1000);
if (!ints.contains(count)) {
ints.add(count);
}
} while (ints.size() < 5);
List<Student> students = new ArrayList<>(Arrays.asList(
new Student(String.valueOf(ints.get(0)), "Ming."),
new Student(String.valueOf(ints.get(1)), "H."),
new Student(String.valueOf(ints.get(3)), "Dai"),
new Student(String.valueOf(ints.get(2)), "JJ."),
new Student(String.valueOf(ints.get(4)), "Sum")
));
System.out.println("=========Before sort=========");
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
System.out.println("=========After sort=========");
Collections.sort(students);
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
System.out.println("=========Sort by name=========");
Collections.sort(students, new StudentComparator());
//students.sort(new StudentComparator()); 也可以写成这个形式
for (Student stu : students) {
System.out.println("#" + stu.id + " " + stu.name);
}
}

浙公网安备 33010602011771号