集合类
参考资料:《Java从入门到精通》/明日科技编著. 4版. 北京:清华大学出版社,2016
一、集合类概述
java.util包中提供了一些集合类,这些集合类又被称为容器。提到集合类不得不想到数组,集合与数组的区别如下:
- 数组用来存放基本类型的数组,集合用来存放对象的引用;
- 数组的长度是固定的,集合的长度是可变的。
常见的集合有List集合、Set集合和Map集合,其中List集合与Set集合继承了Collection接口,各接口还提供了不同的实现类。
上述集合类的继承关系如下所示:
graph LR
Map --> Java.lang.Object
Set --Collention --> Java.lang.Object
List --Collention --> Java.lang.Object
二、Collection接口
- Collection接口是层次结构中的根接口。
- 构成Collection的单元称为元素。
- Collection接口通常不能直接使用,但是该接口提供了添加元素、删除元素和管理数据的方法。
Collection接口常用的方法如下所示:
方法 | 功能描述 |
---|---|
add(E e) | 将指定对象添加到集合中 |
remove(Object o) | 将指定的对象从集合中删除 |
isEmpty() | 判断当前集合是否为空,返回boolean值 |
iterator() | 迭代器,用于遍历集合中的对象 |
size() | 获取该集合中元素的个数,返回int值 |
import java.util.*; //导入java.util包
public class Muster {
public static void main(String[] args) {
//实例化集合对象
Collection<String> list = new ArrayList<>();
//向集合添加元素
list.add("abc");
list.add("def");
//创建迭代器
Iterator<String> it = list.iterator();
//判断是否有下一个元素,遍历集合中的元素
while (it.hasNext()){
String str = (String) it.next();
System.out.println(str);
}
}
}
运行结果:
abc
def
注意:Iterator的next()方法返回的是Object类型。
三、List集合
- List集合包括List接口和List接口的所有实现类。
- List集合中的元素是允许重复的。
- List集合中元素的顺序就是对象插入的顺序。
- 类似Java数组,List集合可以通过索引来访问集合中的元素。
1、List接口
List接口继承了Collection接口,因此包含了Collection接口中的所有方法。此外,List接口还单独定义了两个非常重要的方法,如下所示:
- get( int index ):获得指定索引位置的元素;
- set( int index, Object obj):将集合中指定索引位置的对象修改为指定的对象。
2、List接口的实现类型
List接口的常用实现类有ArrayList和LinkedList。
- ArrayList类
- 优点:实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。
- 缺点:向指定的索引位置插入对象或删除对象的速度较慢。
- LinkedList类
- 优点:采用链表结构保存对象,便于向集合中插入和删除对象,所以需要向集合中插入、删除对象时,使用LinkedList类实现的List集合的效率比较高。
- 缺点:对于随机访问集合中的对象,使用LinkedList类实现List集合的效率比较低。
下面分别通过ArrayList类和LinkedList类实例化List集合:
List <E> list1 = new ArrayList<>();
List <E> list2 = new LinkedList<>();
上述代码中,E是指的合法的Java数据类型。例如,如果集合中的元素为字符串类型,那么E可以修改为String。
import java.util.ArrayList;
import java.util.List;
public class Gather {
public static void main(String[] args) {
//实例化集合对象,设置元素为字符串类型
List <String> list1 = new ArrayList<>();
//向集合中添加对象
list1.add("hello");
list1.add("world");
list1.add("xuliang");
list1.add("xuliang"); //List集合允许元素重复
//获取集合的长度
System.out.println("集合的长度为:" + list1.size());
//遍历集合的元素,元素的顺序就是对象插入集合的顺序
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
System.out.println("-----------------");
//修改指定索引位置的元素
list1.set(2, "happy");
//再次遍历集合
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}
}
运行结果:
集合的长度为:4
hello
world
xuliang
xuliang
-----------------
hello
world
happy
xuliang
从上述代码的运行结果看,集合的索引也是从0开始,与数组一致。
四、Set集合
Set集合中的对象不按照特定的方式排序,只是简单地把对象加入集合,但是Set集合中不允许包含重复对象。
Set集合由Set接口和Set接口的实现类组成,Set接口继承了Collection接口,因此包含Collection接口的所有方法。
注意:Set的构造有一个约束条件,传入的Collection对象不能有重复值,必须小心操作可变对象。
Set接口常见的实现类有HashSet和TreeSet类。
- HashSet类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null元素。
- TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,因此,TreeSet类实现的Set集合在遍历集合时按照自然顺序递增排序,也可以按照指定比较器递增排序,即可以通过比较器对用TreeSet类实现的Set集合中的对象进行排序。
TreeSet集合新增的方法:
方法 | 功能描述 |
---|---|
first() | 返回Set当前第一个(最低)元素 |
last() | 返回Set当前第一个(最高)元素 |
comparator() | 返回对此Set中的元素进行排序的比较器。如果此Set采用自然排序,则返回null |
headSet(E toElement) | 返回一个新的Set集合,新集合是toElement(不包含)之前的所有对象 |
subSet(E fromElement) | 返回一个新的Set集合,是fromElement(包含)对象与fromElement(不包含)对象之间的所有对象 |
tailSet(E fromElement) | 返回一个新的Set集合,新集合包含对象fromElement(包含)之后的所有对象 |
import java.util.Iterator;
import java.util.TreeSet;
public class UpdateStu implements Comparable <Object>{
String name;
long id;
public UpdateStu(String name, long id){
this.name = name;
this.id = id;
}
/*
* id等于updateStu.id,则返回0;
* id大于updateStu.id,则返回1;
* id小于updateStu.id,则返回-1;
*/
@Override
public int compareTo(Object o) {
UpdateStu updateStu = (UpdateStu)o;
int result = (id > updateStu.id)? 1:(id == updateStu.id? 0:-1);
return result;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public static void main(String[] args) {
UpdateStu stu1 = new UpdateStu("李同学", 1001);
UpdateStu stu2 = new UpdateStu("陈同学", 1002);
UpdateStu stu3 = new UpdateStu("王同学", 1003);
UpdateStu stu4 = new UpdateStu("马同学", 1004);
TreeSet <UpdateStu> treeSet = new TreeSet<>(); //实例化TreeSet集合
treeSet.add(stu1); //向集合添加对象
treeSet.add(stu2);
treeSet.add(stu3);
treeSet.add(stu4);
Iterator<UpdateStu> iterator = treeSet.iterator(); //创建Set集合的迭代器
System.out.println("Set集合中的所有元素:");
while (iterator.hasNext()){ //遍历集合
UpdateStu upd = (UpdateStu)iterator.next();
System.out.println(upd.getId() + " " + upd.getName());
}
Iterator<UpdateStu> iterator2 = treeSet.headSet(stu2).iterator(); //截取stu2之前的元素,不包括stu2
System.out.println("截取前面部分的集合:");
while (iterator2.hasNext()){ //遍历集合
UpdateStu upd = (UpdateStu)iterator2.next();
System.out.println(upd.getId() + " " + upd.getName());
}
Iterator<UpdateStu> iterator3 = treeSet.subSet(stu2, stu3).iterator(); //截取stu2~stu3之间的元素,不包括stu3
System.out.println("截取中间部分的集合:");
while (iterator3.hasNext()){ //遍历集合
UpdateStu upd = (UpdateStu)iterator3.next();
System.out.println(upd.getId() + " " + upd.getName());
}
}
}
运行结果:
Set集合中的所有元素:
1001 李同学
1002 陈同学
1003 王同学
1004 马同学
截取前面部分的集合:
1001 李同学
截取中间部分的集合:
1002 陈同学
在上述代码中,存入TreeSet类实现的Set集合必须实现Comparable接口,该接口中的compaareTo(Object o)方法比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、0或正整数。
技巧:headSet()、subSet()、tailSet()方法截取对象生成新集合时是否包含指定的参数,可以通过如下方法判断:如果指定参数位于新集合的起始位置,则包含该对象;如果指定参数是新集合的终止位置,则不包含该对象。
五、Map集合
- Map集合没有继承Collection接口,其提供的是key到value的映射。
- Map中不能包含相同的key,每个key只能映射一个value。
- key还决定了存储对象在映射中的位置,但不是由key对象本身决定的,而是通过一种“散列技术”进行处理,产生一个散列码的整数值。
- Map集合包括Map接口以及Map接口的所有实现类。
1、Map接口
Map接口提供了将key映射到值得对象。Map接口中常见得接口如下所示:
方法 | 功能描述 |
---|---|
put (K key, V value) | 向集合中添加指定的key和value的映射关系 |
containsKey (Object key) | 如果此映射包含key的映射关系,则返回true |
containsValue (Object Value) | 如果此映射将一个或多个key映射到此值,则返回true |
get (Object key) | 如果存在指定的key对象,则返回该对象对应的值,否则返回null |
keySet() | 返回该集合中所有的key对象形成的Set集合 |
values() | 返回该集合中所有的值对象形成的Collection集合 |
import java.util.*;
public class MapInterface {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>(); //创建HashMap集合对象
map.put("1001","李若彤"); //向集合中添加对象
map.put("1002","古天乐");
map.put("1003","周星驰");
Set <String> set = map.keySet(); //构建Map集合中所有key对象的集合
Iterator iterator = set.iterator();
System.out.println("key集合中的元素:");
while (iterator.hasNext()){ //遍历集合
System.out.println(iterator.next());
}
Collection <String> collection = map.values(); //构建Map集合中所有value对象的集合
iterator = collection.iterator();
System.out.println("value集合中的元素:");
while (iterator.hasNext()){ //遍历集合
System.out.println(iterator.next());
}
}
}
运行结果:
key集合中的元素:
1003
1002
1001
value集合中的元素:
周星驰
古天乐
李若彤
说明:Map集合中允许value对象是null,而且没有个数限制。例如,可以通过“map.put("1001", null);”语句向集合中添加对象。
3、Map接口的实现类
Map接口常用的实现类有HashMap和TreeMap类;
- 建议使用HashMap类实现Map集合,因为由HashMap类实现的Map集合添加和删除映射关系效率更高。
- HashMap是基于哈希表的Map接口实现的,HashMap通过哈希码对内部的映射关系进行快速查找。
- TreeMap中的映射关系存在一定的顺序,如果希望Map集合中的对象存在一定的顺序,应该使用TreeMap类实现Map集合。
- HashMap类的特点
- 基于哈希表的Map接口实现,提供所有可选的映射操作,并允许使用null值和null健,但必须保证健的唯一性。
- HashMap通过哈希表对其内部的映射关系进行快速查找。
- HashMap类不保证映射的顺序,特别是它不保证该顺序恒久不变。
- TreeMap类的特点
- TreeMap类不仅实现了Map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。
- 在添加、删除和定位映射关系时,TreeMap类比HashMap类性能稍差。
- 由于TreeMap类实现的Map集合中的映射关系是根据健对象按照一定的顺序排列的,因此不允许对象健对象(key)是null。
可以通过HashMap类创建Map集合,当需要顺序输出时,再创建一个完成相同映射关系的TreeMap类实例。
import java.util.*;
class Emp{
private String e_id;
private String e_name;
public Emp(String e_id, String e_name) {
this.e_id = e_id;
this.e_name = e_name;
}
public String getE_id() {
return e_id;
}
public void setE_id(String e_id) {
this.e_id = e_id;
}
public String getE_name() {
return e_name;
}
public void setE_name(String e_name) {
this.e_name = e_name;
}
}
public class MapTest {
public static void main(String[] args) {
Map <String,String> map = new HashMap<>(); //HashMap实现的Map对象
Emp emp1 = new Emp("123","张三"); //创建对象
Emp emp2 = new Emp("102","李四");
Emp emp3 = new Emp("145","王五");
Emp emp4 = new Emp("110","赵六");
map.put(emp1.getE_id(),emp1.getE_name()); //将对象添加至Map集合中
map.put(emp2.getE_id(),emp2.getE_name());
map.put(emp3.getE_id(),emp3.getE_name());
map.put(emp4.getE_id(),emp4.getE_name());
Set <String> set = map.keySet(); //获取Map集合中的key对象的集合
Iterator <String> iterator = set.iterator();
System.out.println("HashMap实现的Map集合,无序:");
while (iterator.hasNext()){ //遍历集合
String str = (String)iterator.next(); //获取Map集合中的所有key值
String name = map.get(str); //获取Map集合中的所有value值
System.out.println(str + " " + name);
}
TreeMap <String,String> treeMap = new TreeMap<>(); //创建TreeMap集合对象
treeMap.putAll(map); //向TreeMap集合对象中添加Map集合对象,使之具备相同的映射关系
Iterator iterator1 = treeMap.keySet().iterator();
System.out.println("TreeMap实现的Map集合,Key对象升序:");
while (iterator1.hasNext()){ //遍历集合
String str = (String) iterator1.next(); //获取Map集合中的所有key值
String name = treeMap.get(str); //获取Map集合中的所有value值
System.out.println(str + " " + name);
}
}
}
运行结果:
HashMap实现的Map集合,无序:
110 赵六
123 张三
145 王五
102 李四
TreeMap实现的Map集合,Key对象升序:
102 李四
110 赵六
123 张三
145 王五