Java集合类
导言
Java提供了集合类,集合类主要负责保存,盛装其他数据,因此集合类也叫容器类。
集合类和数组不一样,数组元素可以是基本类型的值,也可以是具体对象(实际上是保存的对象的引用变量)而集合只保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。
Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。图 1 和图 2 分别为 Collection 和 Map 的子接口及其实现类。
图1
图二
对于 Set、List、Queue 和 Map 这 4 种集合,Java 最常用的实现类分别是 HashSet、TreeSet、ArrayList、LinkedList 和 HashMap、TreeMap 等。
Collection
常用方法:
Iterator迭代器
Iterator迭代器是集合的输出接口,主要用于遍历输出(即迭代访问)Collection 集合中的元素,Iterator 对象被称之为迭代器。迭代器接口是集合接口的父接口,实现类实现 Collection 时就必须实现 Iterator 接口。因此在使用集合时,选择Iterator代替for循环更高效。
Iterator和ListIterator区别
我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的。
常用方法:
forEachRemaining(Consumer<? super E> action):为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常
hasNext():如果迭代器中还有元素,则返回true。
next():返回迭代器中的下一个元素
remove():删除迭代器新返回的元素
实例
public static void main(String[] Args){
List<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println((String) it.next()); // 输出集合中的元素
}
}
Iterator和ListIterator主要区别在以下方面:
(1)ListIterator有add()方法,可以向List中添加对象,而Iterator不能
(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
(3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。
因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。
List vs Set
相同点: 都表示元素的集合,都相当于一个容器类。
不同点: 一是List集合中的元素是可以重复,而Set集合不允许存在相同的元素;
二是List集合中元素是有序的,而Set集合中的元素可以无序。
List集合
List是一个有序、可重复的集合,集合中每个元素有其对应的顺序索引。可以通过索引来访问元素。
ArrayList类
ArrayList类实现了可变数组的大小。它提供了快速给予索引访问元素的方式,对尾部成员的增删支持较好,但对中间的元素的增删速度较慢。常用方法:
方法名 | 说明 |
---|---|
T get(int index) | 获取索引为index的元素,T为集合的数据类型 |
T set(int index,Element) | 设置索引为index的元素值为Element |
int indexOf(Object o) | 获取元素o对应的索引,不存在返回-1 |
int lastIndexOf(Object o) | 获取元素o最后的索引,不存在返回-1 |
List< T> subList(int fromIndex,int toIndex) | 返回新集合 |
LinkedList类
LinkedList类采用链表结构保存对象,便于向集合中插入和删除元素。
方法名 | 说明 |
---|---|
void addFirst(T e) | 将指定元素添加到此集合的开头 |
void addLast(T e) | 将指定元素添加到此集合的结尾 |
T getFirst() | 返回集合第一个元素 |
T getLast() | 返回集合最后一个元素 |
T removeFirst() | 删除集合第一个元素 |
T removeLast() | 删除集合最后一个元素 |
ArrayList 和 LinkedList 的区别
二者都是List接口的实现类,因此都实现了List的所有方法。
- ArrayList是基于动态数组的数据结构实现,访问速度优于LinkedList;
- LinkedList是基于链表数据结构实现,方便对数据进行插入删除操作,对于批量插入或删除数据时优于ArrayList;
- 对于快速访问对象的需求,使用 ArrayList 实现执行效率上会比较好。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高。
Set集合
Set集合中的对象不按顺序排列,只是简单把对象加入集合,Set集合中元素是不重复的,最多只允许一个null对象。
HashSet
HashSet 具有以下特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。
- HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。
- 集合元素值可以是 null。
- 如果向 Set 集合中添加两个相同的元素,则后添加的会覆盖前面添加的元素,即在 Set 集合中不会出现相同的元素。
Map类
Map是一种键值对(Key-Value)集合。Map接口的常用方法:
方法名 | 描述 |
---|---|
void clear() | 删除该Map对象的所有键值对 |
boolean containsKey(Object key) | 查询Map中是否包含key,存在就返回true |
boolean containsValue(Object value) | 查询Map中是否包含一个或多个value,存在返回true |
T get(Object key) | 通过键key获取对应的值value |
T put(key,value) | 向Map集合添加键值对,若原集合已经存在key,则value覆盖原来的值 |
void putAll(Map m) | 将指定Map的键值对复制到当前map中 |
T remove(object key) | 删除Map集合中key对应的键值对,并返回key对应的value;key不存在就返回null |
boolean remove(Object key,object value) | 删除指定的键值对,成功返回true |
boolean isEmpty() | 查询该Map集合是否为空,为空返回true |
int size() | 返回该Map集合中键值对的个数 |
Set entrySet() | 返回Map集合中所有键值对的Set集合,此Set集合中的元素的数据类型为Map.Entry |
Set keySet | 返回Map集合中所有的键对象的Set集合 |
collection values | 返回该Map集合中所有值value组成的collection集合 |
Map 集合最典型的用法就是成对地添加、删除 key-value 对,接下来即可判断该 Map 中是否包含指定 key,也可以通过 Map 提供的 keySet() 方法获取所有 key 组成的集合,进而遍历 Map 中所有的 key-value 对。
Map集合的遍历
Map集合不同于List集合和Set集合,Map有两组值,因此遍历时可以只遍历键、值,也可以同时遍历,下面看看常见的几种遍历方式。
1)在for循环中使用entry实现Map遍历(最常见和最常用)
Map.Entry 可以看做一个数据类型
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("Java入门教程", "http://c.biancheng.net/java/");
map.put("C语言入门教程", "http://c.biancheng.net/c/");
for (Map.Entry<String, String> entry : map.entrySet()) {
String mapKey = entry.getKey();
String mapValue = entry.getValue();
System.out.println(mapKey + ":" + mapValue);
}
}
2)for-each循环遍历key或者value,一般只适用于只需要Map中的key或value时使用,性能上比entrySet较好。
Map<String, String> map = new HashMap<String, String>();
map.put("Java入门教程", "http://c.biancheng.net/java/");
map.put("C语言入门教程", "http://c.biancheng.net/c/");
// 打印键集合
for (String key : map.keySet()) {
System.out.println(key);
}
// 打印值集合
for (String value : map.values()) {
System.out.println(value);
}
3)使用迭代器(Iterator)遍历
Map<String, String> map = new HashMap<String, String>();
map.put("Java入门教程", "http://c.biancheng.net/java/");
map.put("C语言入门教程", "http://c.biancheng.net/c/");
Iterator<Entry<String, String>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + ":" + value);
}