Java中集合的作用

为了保存数量不确定的数据,以及保存具有映射关系的数据Java 提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类

集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量),而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)

集合类型

Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类

  • Collection的子接口及其实现类
    collection
  • Map 的子接口及其实现类
    collection

上图中接口所代表的作用如下表

接口 作用
Iterator 接口 集合的输出接口,主要用于遍历输出(即迭代访问)Collection 集合中的元素,Iterator 对象被称之为迭代器。迭代器接口是集合接口的父接口,实现类实现 Collection 时就必须实现 Iterator 接口。
Collection 接口 是 List、Set 和 Queue 的父接口,是存放一组单值的最大接口。所谓的单值是指集合中的每个元素都是一个对象。一般很少直接使用此接口直接操作
Queue 接口 Queue 是 Java 提供的队列实现,有点类似于 List
Dueue 接口 是 Queue 的一个子接口,为双向队列。
List 接口 是最常用的接口。是有序集合,允许有相同的元素。使用 List 能够精确地控制每个元素插入的位置,用户能够使用索引(元素在 List 中的位置,类似于数组下标)来访问 List 中的元素,与数组类似。
Set 接口 不能包含重复的元素。
Map 接口 是存放一对值的最大接口,即接口中的每个元素都是一对,以 key➡value 的形式保存。

对于 Set、List、Queue 和 Map 这 4 种集合,Java 最常用的实现类分别是 HashSet、TreeSet、ArrayList、ArrayDueue、LinkedList 和 HashMap、TreeMap 等。下表介绍了集合中这些常用的实现类

类名称 作用
HashSet 为优化査询速度而设计的 Set。它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,实现比较简单
TreeSet 实现了 Set 接口,是一个有序的 Set,这样就能从 Set 里面提取一个有序序列
ArrayList 一个用数组实现的 List,能进行快速的随机访问,效率高而且实现了可变大小的数组
ArrayDueue 是一个基于数组实现的双端队列,按“先进先出”的方式操作集合元素
LinkedList 对顺序访问进行了优化,但随机访问的速度相对较慢。此外它还有 addFirst()、addLast()、getFirst()、getLast()、removeFirst() 和 removeLast() 等方法,能把它当成栈(Stack)或队列(Queue)来用
HsahMap 按哈希算法来存取键对象
TreeMap 可以对键对象进行排序

java Collection 接口

Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用。Collection 接口定义了一些通用的方法,通过这些方法可以实现对集合的基本操作。定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合
(常用的方法有add,clear,isEmpty等,可查询API,但基本的存取要熟记于心,集合类就像容器,现实生活中容器的功能,就是添加对象、删除对象、清空容器和判断容器是否为空等,集合类为这些功能都提供了对应的方法)

应用:创建2个Collection接口的实现类Arrylist的实例对象,并测试基本的存取方法

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
public static void main(String[] args) {
ArrayList list1 = new ArrayList(); // 创建集合 list1
ArrayList list2 = new ArrayList(); // 创建集合 list2
list1.add("one");
list1.add("two");
list1.add("three");
System.out.println("list1 集合中的元素数量:" + list1.size()); // 输出list1中的元素数量
list2.add("two");
list2.add("four");
list2.add("six");
System.out.println("list2 集合中的元素数量:" + list2.size()); // 输出list2中的元素数量
list2.remove(2); // 删除第 3 个元素
System.out.println("\nremoveAll() 方法之后 list2 集合中的元素数量:" + list2.size());
System.out.println("list2 集合中的元素如下:");
Iterator it1 = list2.iterator();
while (it1.hasNext()) {
System.out.print(it1.next() + "、");
}
list1.removeAll(list2);
System.out.println("\nremoveAll() 方法之后 list1 集合中的元素数量:" + list1.size());
System.out.println("list1 集合中的元素如下:");
Iterator it2 = list1.iterator();
while (it2.hasNext()) {
System.out.print(it2.next() + "、");
}
}

输出结果:
结果

List集合:Arrylist类和Linkedlist类

List 是一个有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List 集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。List 集合默认按元素的添加顺序设置元素的索引,第一个添加到 List 集合中的元素的索引为 0,第二个为 1,依此类推。

ArrayList 与 LinkedList 都是 List 接口的实现类,因此都实现了 List 的所有未实现的方法,只是实现的方式有所不同。

ArrayList 是基于动态数组数据结构的实现,访问元素速度优于 LinkedList。LinkedList 是基于链表数据结构的实现,占用的内存空间比较大,但在批量插入或删除数据时优于 ArrayList。

对于快速访问对象的需求,使用 ArrayList 实现执行效率上会比较好。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高。

Set集合:Hashset和Treeset

Set 集合类似于一个罐子,程序可以依次把多个对象“丢进”Set 集合,而 Set 集合通常不能记住元素的添加顺序。也就是说 Set 集合中的对象不按特定的方式排序,只是简单地把对象加入集合。Set 集合中不能包含重复的对象最重要的特点),并且最多只允许包含一个 null 元素

HashSet 类

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时就是使用这个实现类。HashSet 是按照 Hash 算法来存储集合中的元素。因此具有很好的存取和查找性能。

HashSet 具有以下特点:

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
  • HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。
  • 集合元素值可以是 null。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值决定该对象在 HashSet 中的存储位置。如果有两个元素通过 equals() 方法比较返回的结果为 true,但它们的 hashCode 不相等,HashSet 将会把它们存储在不同的位置,依然可以添加成功。

也就是说,两个对象的 hashCode 值相等且通过 equals() 方法比较返回结果为 true,则 HashSet 集合认为两个元素相等。(此时元素不存入集合

创建Hashset对象:

1
2
HashSet hs = new HashSet();    // 调用无参的构造函数创建HashSet对象
HashSet<String> hss = new HashSet<String>(); // 创建泛型的 HashSet 集合对象

Hashset存取的代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
HashSet<String> courseSet = new HashSet<String>(); // 创建一个空的 Set 集合
String course1 = new String("语文");
String course2 = new String("数学");
String course3 = new String("英语");
String course4 = new String("理综");
courseSet.add(course1); // 将 course1 存储到 Set 集合中
courseSet.add(course2); // 将 course2 存储到 Set 集合中
courseSet.add(course3); // 将 course3 存储到 Set 集合中
courseSet.add(course4); // 将 course4 存储到 Set 集合中
System.out.println("高考要考:");
Iterator<String> it = courseSet.iterator();
while (it.hasNext()) {
System.out.println("《" + (String) it.next() + "》"); // 输出 Set 集合中的元素
}
System.out.println( "这"+courseSet.size() + "门课");
}

输出示例:
图片

Treeset类

TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序,因此使用 TreeSet 类实现的 Set 接口默认情况下是自然排序的,这里的自然排序指的是升序排序。

TreeSet 只能对实现了 Comparable 接口的类对象进行排序(如果类不可比较那么必须重写CompareTo方法,不然无法存入Treeset),因为 Comparable 接口中有一个 compareTo(Object o) 方法用于比较两个对象的大小。例如 a.compareTo(b),如果 a 和 b 相等,则该方法返回 0;如果 a 大于 b,则该方法返回大于 0 的值;如果 a 小于 b,则该方法返回小于 0 的值(返回值是正数那么后一个数存入前一个数前面,如果是负数则相反)。

代码示例:(创建person类,并重写compareTo方法,使其可比较)

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
package pratice;

public class preson implements Comparable{
private int age;
private String name;
public preson(String name,int age ){
this.age=age;
this.name=name;
}

public int getAge(){
return this.age;
}

public String getName(){
return this.name;
}
//方法重写
@Override
public int compareTo(Object o) {
preson p=(preson)o;
return (this.age-p.age);

}
}

main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
TreeSet st=new TreeSet<preson>();
preson p1=new preson("褪色者",21);
preson p2=new preson("菈妮",23);
preson p3=new preson("梅玲娜",22);
preson p4=new preson("狼哥",24);
st.add(p1);
st.add(p2);
st.add(p3);
st.add(p4);
//创建一个迭代器
Iterator it=st.iterator();
while(it.hasNext()){
preson p=(preson) it.next();
System.out.println(p.getName()+" "+p.getAge()+"岁");
}
}

输出示例
图片

map集合:Hashmap和Treemap

Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键(key)对象和一个值(value)对象。用于保存具有映射关系的数据。

Map 集合里保存着两组值,一组值用于保存 Map 里的 key,另外一组值用于保存 Map 里的 value,key 和 value 都可以是任何引用类型的数据。Map 的 key 不允许重复,value 可以重复,即同一个 Map 对象的任何两个 key 通过 equals 方法比较总是返回 false。

Map 中的 key 和 value 之间存在单向一对一关系,即通过指定的 key,总能找到唯一的、确定的 value。从 Map 中取出数据时,只要给出指定的 key,就可以取出对应的 value。

Map 集合最典型的用法就是成对地添加、删除 key-value 对,接下来即可判断该 Map 中是否包含指定 key,也可以通过 Map 提供的 keySet() 方法获取所有 key 组成的集合,进而遍历 Map 中所有的 key-value 对。下面程序示范了 Map 的基本功能。

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
public static void main(String[] args) {
HashMap users = new HashMap();
users.put("11", "张浩太"); // 将学生信息键值对存储到Map中
users.put("22", "刘思诚");
users.put("33", "王强文");
users.put("44", "李国量");
users.put("55", "王路路");
System.out.println("******** 学生列表 ********");
Iterator it = users.keySet().iterator();
while (it.hasNext()) {
// 遍历 Map
Object key = it.next();
Object val = users.get(key);
System.out.println("学号:" + key + ",姓名:" + val);
}
Scanner input = new Scanner(System.in);
System.out.println("请输入要删除的学号:");
int num = input.nextInt();
if (users.containsKey(String.valueOf(num))) { // 判断是否包含指定键
users.remove(String.valueOf(num)); // 如果包含就删除
} else {
System.out.println("该学生不存在!");
}
System.out.println("******** 学生列表 ********");
it = users.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
Object val = users.get(key);
System.out.println("学号:" + key + ",姓名:" + val);
}
}

输出示例:
输出

TreeMap 类的使用方法与 HashMap 类相同,唯一不同的是 TreeMap 类可以对键对象进行排序(参照Hashset和Treeset)