概述
- JDK1.2时候,Java的设计者们对Java存储数据的容器进行了大刀阔斧的改革。推出了庞大的Java集合框架体系。
- Java集合框架拥有非常庞大的容器体系,通过不同的实现对不同场景的元素存取达到高性能。
- Java集合拥有2大常用分支,一支是Collection体系的存储单个元素的集合,另一分支存储着Key——Value健值对形式的Map体系。
- Collection体系中,又拥有3大常用分支分为List,Queue,Set。
- 而Map体系中,分为无序Key-Value和有序Key-Value形式2大类。
- 集合的子类非常多,本文将介绍常用的集合实现类。
- 下图展示了集合的继承关系,通过掌握继承关系图,可以更加容易学习集合框架。
Java常用集合类架构图
Java Map 集合类架构图
Collection 接口
- 整个Collection接口是集合的根接口,Collection用来描述一组对象,描述集合这个概念
- 同时Collection也提供了基本操作集合的方法
- 一些 Collection 允许有
重复的元素,而另一些则不允许。一些 Collection 是有序的,而另一些则是无序的。
- Collection子接口分为常用的三大分支:List(有序集合)Queue(队列)Set(无序不可重复)
- Collection 规范了集合的常用方法,包含添加,删除,是否包含,迭代器等常用功能。
List 接口
- List接口用来描述一组
有序集合,集合记录元素插入顺序。
- List接口允许用户
通过索引对元素精准控制,包括插入,修改,访问元素。
- List接口通常
允许元素重复。
- List 接口在Collection接口基础上,提供了更多通过索引操作元素
ArrayList
- List 接口的
可变数组的实现类,其拥有父接口List有序集合,索引控制,重复元素的等特点。
- 允许插入null所在内的元素。
- 此类还提供一些方法来
操作内部用来存储列表的数组的大小。
- 在添加元素前,ArrayList使用
ensureCapacity 操作来增加容量。
// 1. 创建ArrayList对象
ArrayList<String> list = new ArrayList<>();
//2. 添加设置元素的值
list.add("hello");
list.add(1, "world");
list.add("java");
//3. 删除元素
list.remove("world");
list.remove(0);
//4. 修改元素的值
list.set(0,"Hello");
//5. 查询相关
list.get(0);
list.forEach((String e) -> {
System.out.println("e = " + e);
});
Vector
- Vector 是JDK1.0提供的集合类。
- Vector 的底层实现与
ArrayList相同,并提供了ArrayList相同的功能。
- Vector 所有方法都通过增加
synchronized来实现线程安全。
- Vector 是线程安全的,但同时
效率相比ArrayList较低,在JDK1.2中,ArrayList是Vector的替代方法,推荐使用ArrayList。
LinkedList
- List接口的双向链表实现。
- 其拥有父接口List有序集合,索引控制,重复元素的等特点。
- LinkedList 在操作列表,头元素,尾元素 (get、remove、insert)时,提供了
统一的命名方式,所以LinekedList 这些操作允许将链表当作栈、队列或双端队列使用。
- LinekedList所有操作都是按照
双向链表方式执行的,当按索引获取/修改/插入元素时,将从开头或结尾遍历链表(从靠近指定索引的一端)。
- LinkedList 由于双向链表的特性,以及实现了Queue,和Dequeue接口,将而外提供栈,和双端队列的特点。

6. 作为队列使用的LinkedList
LinkedList<String> queue = new LinkedList<>();
// 向队列头插入元素
queue.offer(" world");
// 默认 linked last
queue.offer("hello");
queue.offerFirst("java");
//queue = [java, world, hello]
System.out.println("queue = " + queue);
// 获取 队列 头、尾元素,但不移除
String v = queue.peek();
v = queue.peekFirst();
v = queue.peekLast();
// 获取 队列 头、尾元素,并且移除出队列
v = queue.poll();
v = queue.pollLast();
- 作为栈使用的LinkedList
LinkedList<String> stack = new LinkedList<>();
stack.push("hello");
stack.push("world");
stack.pop();
stack.pop();
Queue & Deque
- Queue队列维护着一个先进先出(First In First Out)数据结构
- Queue接口与List、Set同一级别,都是继承了Collection接口。
- Deque一个线性 Collection,支持在两端插入和移除元素。名称 deque 是“double ended queue(双端队列)”的缩写。
- 此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。
- LinkedList使用双向链表实现了基本的队列操作
Set
- Set集合在Collection集合基础上 提供
不包含重复元素的功能。
- Set不包含满足
e1.equals(e2)或(el==e2) 的元素,并且最多包含一个 null 元素。
- Set集合一般
不维护着元素的插入顺序。
- 同时Set集合不提供对索引精准控制。
- Set实现类底层采用
与之名称对应Map实现类实现,通过将元素存储在Map的Key中,Value采用全局静态Object的实例。
- Set接口提供着和Collection相同的方法列表规定。

HashSet
- Set集合基于哈希表实现类---对应HashMap。
- HashSet
内部使用HashMap的key来存储元素,value使用静态的Object对象实例。
- HashSet提供了Set接口的所有方法的实现,在判断是
否包含某元素和删除插入元素上,拥有卓越的性能。
LinkedHashSet
- LinkedHashSet
可预知迭代顺序Set接口的实现类,基于哈希表+双向链表实现---对应LinkedHashMap。
- LinkedHashSet
继承自 HashSet。
- 通过调用父类接收3个参数构造方法,在内部初始化LinkedHashMap存储元素,所以其实现代码写在父类里,但父类HashMap此初始化方法是 默认 修饰符,只有包访问权限,所以只能子类初始化。
- 与 HashSet 的不同之外在于,后者在哈希表的基础上,增加了一个维护所有条目的双向链表,此链表定义了迭代顺序,即插入元素顺序。
TreeSet
- TreeSet
可排序的Set接口的实现类---对应TreeMap。
- TreeSet 内部使用了
TreeMap(红黑树)实现排序功能,同样将元素作为TreeMap的Key。
- TreeSet 默认使用元素的
自然排序,元素需要实现Comparable接口。
- TreeSet 同时允许,通过传递
比较器(Comparator)实现类,自定义排序。
// TreeSet 自然排序
TreeSet<Integer> set = new TreeSet<>();
set.add(10);
set.add(7);
set.add(2);
set.add(9);
// set = [2, 7, 9, 10]
System.out.println("set = " + set);
// 实现 Comparator 接口,自定义排序
TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
num = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
return num;
}
});
Map<K,V>
- Map接口是Map体系的根接口。
- Map特点是将键映射到值的对象,每个键最多只能映射到一个值
- Map中同样相同的健只能存储一个。

HashMap<K,V>
- HashMap是Map接口基于
哈希表的实现类。
- 其拥有Map接口的所有实现方法。
- HashMap不保证映射的顺序,即插入元素的顺序。
- 关于哈希表的实现,请参考。
LinkedHashMap<K,V>
- LinkedHashMap是Map接口
哈希表和链表的实现。
- 其拥有Map接口所有的方法,并具有可预知的迭代顺序。
- 后者维护着一个运行于所有条目的
双重链表。此链表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序。
Hashtable<K,V>
- Hashtable 与 HashMap同样是基于
哈希表实现类。
- Hashtable 是JDK1.0推出的键值映射集合,在JDK1.2后此类就被改进以实现 Map 接口。
- Hashtable不保证映射的顺序,即插入元素的顺序。
- 与HashMap不同的是,Hashtable所有方法都是线程同步的。
Properties
- Properties 类是Hashtable的子类,其同样是键值映射集合。
- 不同的是 Properties类表示了一个
持久的属性集。
- Properties 可以配合IO流,从
流中读取或将数据写入流中。
- Properties 中每个键及其对应值
都是一个字符串。
- 使用 Properties 时,
不建议使用 put 和 putAll 方法,因为他们允许插入String之外的值。
- Java开发中,常常将一些
配置信息存放在.properties文件中,而使用Properties类的load方法进行加载。

7. 使用Properties存储键值对,并存储到文件中。
Properties p = new Properties();
p.setProperty("name","李洛克");
p.setProperty("age","18");
// 将 properties 保存到 classPath 路径下
String classPath = ClassLoader.getSystemResource("").getPath();
OutputStream os = new FileOutputStream(classPath + "test.properties");
p.store(os,"注释");
// 所谓classpath 就是指使用 javac -d classpath 的路径
// 在idea中就是 project compiler output path
// maven 工程会自动将 标记为 resources 文件夹下文件拷贝到classpath路径下
- 读取文件中properties的内容
// 从 classPath 下加载 properties文件
InputStream is = ClassLoader.getSystemResourceAsStream("test.properties");
Properties p = new Properties();
p.load(is);
System.out.println(p.getProperty("name"));
System.out.println(p.getProperty("age"));
TreeMap<K,V>
- 可自然排序和自定义规则排序的Map集合。
- TreeMap 是基于红黑树(Red-Black tree)的 NavigableMap 接口的实现。
- 使用TreeMap实现排序方法
// 自定义元素排序,按照key的长度 进行排序
Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
map.put("a",1);
map.put("bbbb",1);
map.put("ccc",1);
// map = {a=1, ccc=1, bbbb=1}
System.out.println("map = " + map);