Java集合

Java集合框架:Collection接口,Map接口,Collections工具类,Comparable接口,Comparator接口

集合

Java中的集合类是一种工具类,用于存储任意数量的具有共同属性的对象

集合的作用:

  1. 在类的内部,对数据进行组织
  2. 简单而快速的搜索大数量的条目
  3. 有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除有关元素
  4. 有的集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型

集合和数组的区别:

  1. 数组的长度固定,集合长度可变
  2. 数组只能通过下标访问元素,类型固定,而有的集合可以通过任意类型查找所映射的具体对象


Collection(接口)

  • List(接口)(特点:有序,可重复)
    • ArrayList(实现类)
    • LinkedList(实现类)
  • Query(接口)(特点:有序,可重复)
    • LinkedList(实现类)
  • Set(接口)(特点:无序,不可重复)
    • HashSet(实现类)
      Map(接口)(特点:Entry(Key,Value) – 键值对:)注:Entry是Map的内部类
  • HashMap(实现类)

Collection接口是List、Set和Queue接口的父接口,定义了可用于操作List、Set和Queue的方法————增删改查

List

List是元素有序并且可以重复的集合,被称为序列
List可以精确的控制每个元素的插入位置,或删除某个位置元素

ArrayList(数组列表)是List的一个重要实现类,底层是由数组实现的

list.add(对象)把一个对象添加到另一个集合的队尾位置
list.add(index, 对象) 把一个集合添加到另一个集合的指定位置
list.addAll(集合对象) 把一个集合添加到另一个集合的队尾位置
list.addAll(index, 集合对象) 把一个集合添加到另一个集合的指定位置
Arrays.asList(数组) 把一个数组转换成List集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class Course {
public String id;
public String name;
public Course(){}
public Course(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Course{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Course course = (Course) o;
return Objects.equals(name, course.name);
}
}
/**
* 模拟学生选课功能
* 1. 添加课程
* 2. 删除课程
* 3. 查看所选课程
* 4. 修改所选选课程
*/
public class ListTest {
public List coursesList;
public ListTest(){
this.coursesList = new ArrayList();
//List是接口,所以在构造方法中不能直接实例化,而通过ArrayList()实例化
}
/**
* 添加课程
*/
public void courseAdd(){
Course course1 = new Course("1","数据结构");
Course course2 = new Course("2","离散数学");
Course course3 = new Course("3","高等数学");
Course course4 = new Course("4","计算机组成原理");
Course course5 = new Course("5","计算机网络");
Course course6 = new Course("6","大学英语");
coursesList.add(course1);
coursesList.add(course1);
//支持重复数据
//coursesList.add(2,course2);
//会报异常IndexOutOfBoundsException: Index: 2, Size: 1
coursesList.add(1,course2);
Course[] courses1 = {course3,course4};
coursesList.addAll(Arrays.asList(courses1));
Course[] courses2 = {course5,course6};
coursesList.addAll(2,Arrays.asList(courses2));
}
/**
* 遍历课程
*/
public void coursesGetAll(){
for(int i = 0;i<coursesList.size();i++){
Course course = (Course) coursesList.get(i);
//get()方法获得的对象是Object类型,需要转换
System.out.println(course);
}
System.out.println("-----------------");
//foreach遍历方法
for(Object object : coursesList){
System.out.println((Course)object);
}
System.out.println("-----------------");
//迭代器遍历
Iterator iterator = coursesList.iterator();
while(iterator.hasNext()){
System.out.println((Course)iterator.next());
}
System.out.println("-----------------");
}
/**
* 修改课程
*/
public void courseSet(){
Course course = new Course("7","Java web");
coursesList.set(0,course);
}
/**
* 删除课程
*/
public void courseRemove(){
coursesList.remove(coursesList.get(1));
coursesList.remove(2);
Course[] courses = {(Course) coursesList.get(3),(Course) coursesList.get(4)};
coursesList.removeAll(Arrays.asList(courses));
}
/**
* 索引课程位置
* indexOf()方法返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
*/
public int courseIndex(Course course){
return coursesList.indexOf(course);
}
/**
* 判断课程是否存在
*/
public boolean courseContain(Course course){
/**
* ArrayList中contains() 如果此列表中包含指定的元素,则返回 true。
* 更确切地讲,当且仅当此列表包含至少一个满足 (o==null ? e==null : o.equals(e)) 的元素 e 时,则返回 true。
* 因此比较的是o.equals(e),这是比较两个对象内在地址是否相同
* 这里只需要比较课程的名称是否相同,重写Course类的equals方法
*/
return this.coursesList.contains(course);
}
public static void main(String[] args){
ListTest listTest = new ListTest();
listTest.courseAdd();
listTest.coursesGetAll();
// listTest.courseRemove();
// listTest.coursesGetAll();
listTest.courseSet();
listTest.coursesGetAll();
Course course = (Course)listTest.coursesList.get(0);
System.out.println(listTest.courseContain(course));
Course course1 = new Course("1","数据结构");
//重写Course类的equal方法前为false,重写后为true
System.out.println(listTest.courseContain(course1));
System.out.println(listTest.courseIndex(course1));
}
}

集合中的元素可以是任意类型的对象,如果把某个对象放入集合,则会忽略它的类型,而把它当做Object对象处理。泛型则规定了某个集合只可以存放特定类型的对象,会在编译期间进行类型检查
比如上例中的List未规定泛型,则coursesList除了可以添加Course对象外,还可以添加String类型等其他类型,而且在取出其中的元素时,需要进行类型转换

用泛型改进上例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class ListGenericTest {
public List<Course> courseList;
public ListGenericTest(){
this.courseList = new ArrayList<Course>();
}
public void courseAdd(){
Course course1 = new Course("1","数据结构");
Course course2 = new Course("2","离散数学");
Course course3 = new Course("3","高等数学");
Course course4 = new Course("4","计算机组成原理");
Course course5 = new Course("5","计算机网络");
Course course6 = new Course("6","大学英语");
courseList.add(course1);
courseList.add(course1);
courseList.add(1,course2);
Course[] courses1 = {course3,course4};
courseList.addAll(Arrays.asList(courses1));
Course[] courses2 = {course5,course6};
courseList.addAll(2,Arrays.asList(courses2));
}
public void coursesGetAll(){
for(Course course:courseList){
System.out.println(course);
}
System.out.println("-----------------------");
}
/**
* 修改课程
*/
public void courseSet(){
Course course = new Course("7","Java web");
courseList.set(0,course);
}
public void courseRemove(){
courseList.remove(courseList.get(1));
courseList.remove(2);
Course[] courses = {courseList.get(3),courseList.get(4)};
courseList.removeAll(Arrays.asList(courses));
}
public static void main(String[] args){
ListGenericTest listTest = new ListGenericTest();
listTest.courseAdd();
listTest.coursesGetAll();
listTest.courseRemove();
listTest.coursesGetAll();
listTest.courseSet();
listTest.coursesGetAll();
}
}

泛型不还可以接受泛型类的子类型

1
2
3
4
5
6
7
public class ChildCourse extends Course {
}
public void childCourseAdd(){
ChildCourse childCourse = new ChildCourse();
courseList.add(childCourse);
}

泛型集合中的限定类型不能使用基本数据类型,可以通过包装类使用基本数据类型

1
List<Integer> lists = new ArrayList<>();

Set

Set是元素无序并且不可以重复的集合,被称为集

HashSet(哈希集)是Set的一个重要实现类。

  1. Set没有像List中set()方法一样就修改,因为List是有序的,可以指定位置,而Set是无序的。
  2. 查询遍历时,Set不能用get()方法去获取,因为无序没有指定索引ID,但可以使用foreach和iterator来遍历,但是每次遍历出来可能顺序都不一样,还是因为无序造成的。
  3. Set中的size(),add(),addAll(),remove(),removeAll()与List类似。
  4. Set还可以添加null,new HashSet<>().add(null);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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<>();//初始化集合
}
}
public class SetTest2 {
public static void main(String[] args){
Student student = new Student("1","小明");
Course course1 = new Course("1","数据结构");
Course course2 = new Course("2","离散数学");
Course course3 = new Course("3","高等数学");
//增加课程
student.courses.add(course1);
List<Course> courseList = new ArrayList<>();
courseList.add(course2);
courseList.add(course3);
student.courses.addAll(courseList);
//遍历课程
//不能使用get方法遍历,因为Set是无序的
for(Course course:student.courses){
System.out.println(course);
}
//移除课程
student.courses.remove(course3);
for(Course course:student.courses){
System.out.println(course);
}
//判断Set中是否包含课程
//使用contains方法
System.out.println(student.courses.contains(course1));//true
Course course4 = new Course("1","数据结构");
//返回false,HashSet类的contain方法,需要比较hashcode方法和equals方法
//重写hashcode方法和equals方法后,才为true
System.out.println(student.courses.contains(course4));
}
}

Map

  1. Map接口提供了一种映射关系,其中的元素是键值对(key-value)的形式存储的,能够实现根据Key快速查找value。Key-value可以是任何对象,是以Entry类型的对象实例存在的。
    2.Key是不可以重复的,Value是可以重复的。Key-value都可以为null,不过只能有一个key是null。
    3.map支持泛型,Map
    4.每个键最多只能映射到一个值
    5.Map接口提供了分别返回key值集合(keySet())、value值集合(values())以及Entry(键值对)集合(entrySet() )的方法

HashMap是Map的一个实现类,基于哈希表实现,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

  • Key值和value值都可以为null,但是一个HashMap只能有一个key值为null的映射(key值不可重复)
  • HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。
  • 如果需要同步,可以用Collections.synchronizedMap(HashMap map)方法使HashMap具有同步的能力。
  • Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;
  • HashMap中的Entry对象是无序排列的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* 通过Map<String,Student>进行学生信息管理,其中key为学生ID,value为学生对象
* 对集合中的学生信息进行增、删、改、查操作
*/
public class MapTest {
public Map<String,Student> studentMap;
public MapTest(){
this.studentMap = new HashMap<>();
}
/**
* 增加学生信息
* @param student
*/
public void studentAdd(Student student){
Student student1 = studentMap.get(student.id);
if(student1 != null){
System.out.println("学生id已存在");
return ;
}
studentMap.put(student.id,student);
}
/**
* 查找学生信息
* @param id
* @return
*/
public Student studentGet(String id){
Student student = studentMap.get(id);
if(student != null){
return student;
}else {
return null;
}
}
/**
* 遍历学生信息
* @return
*/
// public Map<String,Student> studentGetAll(){
// return this.studentMap;
// }
public void studentGetAll(){
Set<Map.Entry<String,Student>> entrySet = studentMap.entrySet();
for(Map.Entry<String,Student> entry:entrySet){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
/**
* 修改学生信息
* @param student
*/
public void studentModify(Student student){
Student student1 = this.studentGet(student.id);
if(student1 == null){
System.out.println("学生id不存在");
return;
}
studentMap.put(student.id,student);
}
/**
* 测试Map中是否包含某个key或者value值
* 在Map中,用containsKey方法,来判断是否包含某个key值
* 在Map中,用containsValue方法,来判断是否包含某个Value值,需要重写equals方法和hashCode方法
* @param id
* @return
*/
public void studentContainsById(String id){
if(studentMap.containsKey(id)){
System.out.println("该学生存在");
}else{
System.out.println("该学生不存在");
}
}
//注意,Map的值为Student类
public void studentContainsByName(String name){
if(studentMap.containsValue(new Student(null,name))){
System.out.println("该学生存在");
}else{
System.out.println("该学生不存在");
}
}
/**
* 删除学生信息
* @param id
*/
public void studentDelete(String id){
Student student1 = this.studentGet(id);
if(student1 == null){
System.out.println("学生id不存在");
return;
}
studentMap.remove(id);
}
public static void main(String[] args){
MapTest mapTest = new MapTest();
mapTest.studentAdd(new Student("1","John"));
mapTest.studentAdd(new Student("2","John"));
mapTest.studentAdd(new Student("3","Mei"));
mapTest.studentGetAll();
System.out.println(mapTest.studentGet("3"));
System.out.println(mapTest.studentGet("5"));
Student student = new Student("2","Halen");
mapTest.studentModify(student);
Student student1 = new Student("5","Halen");
mapTest.studentModify(student1);
mapTest.studentGetAll();
mapTest.studentDelete("1");
mapTest.studentGetAll();
mapTest.studentDelete("4");
System.out.println();
mapTest.studentGetAll();
mapTest.studentContainsById("1");
mapTest.studentContainsById("2");
mapTest.studentContainsByName("Mei");
mapTest.studentContainsByName("Halen");
}
}

contains方法

contains方法用于判断集合中是否包含某个值

不论是List中的 contains 方法,Set中的 contains 方法,以及Map中的 containsKeycontainsValue ,都是遍历寻找第一个匹配的项,因为使用的是equals 方法,所以比较的是对象的引用是否相同,即是否是同一个对象,需要重写类的equals 方法,另外Set的contains 方法和Map中的 containsValue 需要重写 hashCode 方法

Conllections工具类

java.util.Collections工具类是Java集合框架中用来操作集合对象的工具类

排序

根据元素的自然顺序对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable 接口。

两个接口都可以使用泛型

Comparable接口

定义了默认的比较规则
实现该接口表示:这个类的实例可以比较大小,可以进行自然排序

实现 Comparable 接口必须实现 compareTo 方法,该方法比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

Comparator接口—–比较工具接口

定义了临时的比较规则

其实现类需要实现 compare()方法,该方法比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
public class Student implements Comparable<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<>();//初始化集合
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
return this.id.compareTo(o.id);
}
}
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class CollectionsTest {
/**
* 通过Collections.sort()方法对Integer泛型的List进行排序
*/
public static void IntegerSort(){
List<Integer> integerList = new ArrayList<>();
for(int i=0; i<10;i++){
integerList.add((int)(Math.random()*100));
}
for(Integer i :integerList){
System.out.print(i+"\t");
}
System.out.println();
Collections.sort(integerList);
for(Integer i :integerList){
System.out.print(i+"\t");
}
}
/**
* 对String泛型的List进行排序
* 字符串的排列顺序为 1.0-9 2.A-Z 3.a-z
*/
public static void StringSort(){
List<String> stringList = new ArrayList<>();
for(int i=0;i<5;i++){
stringList.add(randomString1(10));
}
for(String s :stringList){
System.out.print(s+"\t");
}
System.out.println();
Collections.sort(stringList);
for(String s :stringList){
System.out.print(s+"\t");
}
}
/**
* 创建给定长度的随机字符串
* @param i
* @return
*/
public static String randomString(int i){
String s = "";
short start = '0';
short end = 'z' + 1;
while (s.length() != i) {
char c = (char) (Math.random() * (end - start) + start);
if (Character.isDigit(c) || Character.isLetter(c)) {
s += c;
}
}
return s;
}
/**
* 创建给定长度以内的随机字符串
* 每条字符串的长度为i以内的随机整数
* 每条字符串的每个字符都为随机生成的字符,字符可以重复
* @param i
* @return
*/
public static String randomString1(int i){
String s = "";
short start = '0';
short end = 'z' + 1;
//避免字符串长度为0
int x = (int)(Math.random()*(i-1)+1);
while (s.length() != x) {
char c = (char) (Math.random() * (end - start) + start);
if (Character.isDigit(c) || Character.isLetter(c)) {
s += c;
}
}
return s;
}
/**
* 实现Comparatable接口,根据字符串id比较
*/
public static void StudentSort(){
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("3","Halen"));
studentList.add(new Student("2","John"));
studentList.add(new Student("1","JJ"));
for(Student s:studentList){
System.out.print(s);
}
System.out.println();
Collections.sort(studentList);
for(Student s:studentList){
System.out.print(s);
}
}
/**
* 实现Comparator接口,根据名字比较
*/
public static void StudentSort2(){
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("3","Halen"));
studentList.add(new Student("2","John"));
studentList.add(new Student("1","JJ"));
for(Student s:studentList){
System.out.print(s);
}
System.out.println();
Collections.sort(studentList,new StudentComparator());
for(Student s:studentList){
System.out.print(s);
}
}
public static void main(String[] args){
CollectionsTest.IntegerSort();
System.out.println();
CollectionsTest.StringSort();
System.out.println();
CollectionsTest.StudentSort();
System.out.println();
CollectionsTest.StudentSort2();
}
}