[toc]
List集合
graph LR
List-->ArrayList
List-->LinkList
List-->Vector
- ArrayList集合
- 底层采用数组数据结构
- 线程不安全
- LinkList集合底层采用双向链表数据结构。
- Vector集合
- 底层采用数组数据结构
- 线程安全
Vector 的效率低,原因:底层的方法都采用
synchronized关键字保证线程安全,现在保证线程安全有其他方案,使用较少。
Set集合
graph LR
Set-->HashSet
Set-->AbstractSet
AbstractSet-->TreeSet
- HashSet集合
- 底层是
new了一个HashMap对象,向HashSet中存储数据,实际上是存储在HashMap中 - 底层采用哈希表数据结构
- 底层是
- TreeSet集合
- TreeSet 继承 AbstractSet,而AbstractSet实现了Set接口,本身没有实现Set接口
- 底层
new了一个TreeMap对象,向TreeSet中存储数据,实际上是存储在TreeSet中 - 底层采用二叉树数据结构
Map集合
graph LR
Map-->HashMap
Map-->Hashtable
Map-->AbstractMap
AbstractMap-->TreeMap
Hashtable-->Properties
- HashMap集合
- 底层是哈希表数据结构,非线程安全
- Hashtable集合
- 底层是哈希表数据结构,线程安全
- 效率低
- TreeMap集合
- 底层是二叉树数据结构
- Properties集合
- 因为继承Hashtable,所以线程是安全的。
- Properties的Key和Value只支持String类型,所以Properties被称为属性类
Map集合和Collection集合没有关系,Map集合以Key和Value的这种键值对的方式存储元素,Key和Value都是存储java对象的内存地址,所有Map集合的Key特点:无序不可重复,Map集合的Key和Set集合存储的元素特点相同
Hashtable具体情况和Vector相同,所有方法都有
synchronized关键字保证线程安全
HashSet
- 存储时顺序和取出的顺序不同
- 不可重复
- 放到HashSet集合中的元素实际上是放到HashSet集合的key部分
Vector
- 底层为数组
- 初始化容量为10
- 扩容之后是原容量的2倍
- 所有方法都是带有线程同步的,带有cynchronized,是线程安全的,效率低。
LinkList集合
- 有下标
- 底层是双向链表
- 没有初始化容量
- 最初链表中没有元素,first和last都是null
链表的优点: 由于链表上元素在空间存储上内存地址不连续,所以增删不会有大量元素位移,因此效率高。
链表的缺点:不能通过数学表达式计算被查找元素的内存地址,每一次查找都要从头开始遍历,直到找到为止,因此查找效率低
ArrayList集合
- 初始化容量是==10==,底层先创建一个长度为0的数组,当添加第一个元素的时候,初始化为==10==
- 底层是一个
Object类型的数组 - 构造方法
- new ArrayList(); - new ArrayList(int initialCapacity); - 集合的扩容,原集合的1.5倍
- 优化
- 尽可能少扩容。因为数组扩容效率比较低,建议在初始的时候定容量,减少数组的扩容次数
- 优点
- 检索效率高
- 缺点
- 随机增删效率低
- 数组无法存储大数据量
- 向数组末尾添加效率高,不受影响
HashMap
- 初始化容量为16
- 当底层的容量达到75%,数组开始扩容
- HashMap集合的初始化容量必须是2的倍数,也是官方推荐的,这是为了达到散列均匀,提高集合的存储效率
- 向集合中存储,会先调用key的
hashCode()方法,然后调用equals()方法 - 非线程安全
- 单向链表中的元素超过8个,会变成红黑树。但红黑树的节点数量小于6时,会重新变成单向链表。
- 允许key为
null
Hashtable
- 底层时哈希表
- key和value不能为空
- 线程安全,效率低
- 初始化11,当达到75%时扩容
- 扩容:原容量 * 2 + 1
Properties
- 是一个Map集合,继承Hashtable
- key和value都是String类型
- 被称为属性类对象
- 线程安全
TreeSet
-
底层是TreeMap的Key
-
无序不可重复
-
存储的元素会自动按照大小顺序排序
-
底层是一个二叉树
-
TreeSet无法对自定义类型排序
- 原因没有实现
Comparable<T>接口 - 没有在构造集合的时候给他传一个比较器对象
Comparator
当比较规则不会发生改变的时候用
Comparable<T>接口当比较规则多的时候使用
Comparator<T>接口Comparator<T>接口符合OCP原则 - 原因没有实现
自平衡二叉树
- 遵循左小右大原则存放
- 遍历的方式
- 前序遍历:根左右
- 中序遍历:左根右
- 后序遍历:左右根
TreeSet集合/TreeMap集合采用中序遍历方式

哈希表
- 哈希表是一种数组和单向链表的结合体。
- 数组:在查询的方面效率高,随机增删效率低。
- 单向链表:在随机增删方面效率高,查询效率低。
- HashMap源码
//Hash底层实际上就是一个数组
transient Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;//哈希值(哈希值是key的hashCode()方法的执行结果hash值通过哈希函数/算法,可以转换存储成数组的下标)
final K key;
V value;
Node<K,V> next;//下一个节点的内存地址
}
- 哈希表/散列表:一堆数组,这个数组中的每一个元素是一个单向链表。(数组和链表的结合体)
map.put(k,y)实现原理- 先将k,y封装到Node对象
- 底层调用
hashCode()方法得出hash值,然后通过哈希算法/哈希函数,然后将哈希值转换成数组的下标。如果下标有对应的位置有链表,会将k值与链表上的k值进行equals()比较,如果都是false,那么将会添加到链表的末尾。如果是true,那么这个节点的value将会被覆盖。
map.get(k)实现原理- 调用k的
hashCode()方法得出哈希值,通过哈希算法/哈希函数转换成数组下标,通过数组下标来定位,如果没有返回null。如果有单向链表,则会与所有节点的k进行equals()方法,返回false则输出null,返回true则输出该节点的value值。
- 调用k的
- 散列分布
- 散列发布不均匀
- 将
hashCode()方法返回固定某个值或者都不一样,导致哈希表变成纯单向链表
- 将
- 散列发布均匀
- 例如假设有100个元素,10个单向链表,每个链表10个节点
- 散列发布不均匀

同一个单向链表上的hash值相同。 重点:放在HashMap集合的key元素和放在HashSet集合中的元素,需要同时重写hashCode()和equals()方法