概述
- List、Set和Map都是接口,其中List和Set都是继承自Collection接口,而Map是单独的接口
- List :元素可重复,有序(即可知元素的添加顺序),具体实现有ArrayList,LinkedList,Vector
- Set:集合元素不可重复(元素唯一),无序(LinkedHashSet实现了有序),具体实现有HashSet,LinkedHashSet,TreeSet
- Map:键值对集合,键必须唯一,具体实现有HashMap,HashTable,TreeMap。
特点总结
先放上自己学习时记录的思维导图。
Collection:
— List:元素可重复,有序
- ArrayList: 常用,底层结构是数组,具有数组的特点,默认初始化容量为10
优点:查询快,效率高
缺点: 增删慢,线程不安全
扩容: 底层扩容代码为 oldCapacity + (oldCapacity >> 1),>>为位运算,左移一位,变为原来的1/2。即默认容量为10,扩容为原来的1.5倍,元素数量超过10时新建一个容量为15的Arraylist,再将原列表的元素copy过去 - LinkedList:底层是链表,线程不安全
优点:增删快,效率高
缺点:查询慢 - Vector: 同Arraylist,底层是数组,但大部分public方法添加了锁,线程安全
优点:查询快,线程安全
缺点:增删慢,效率低
扩容:可自己指定扩容大小,默认为扩容一倍,如默认容量为10,第一次扩容后变为20。
— Set: 元素不可重复,唯一,无序
-
HashSet: 底层是HashMap,key为要添加的元素,value为Object类型的常量。通过hashCode和equals方法保证元素的唯一性。
扩容:默认容量为16,负载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容;
扩容增量为原容量的 1 倍,如 HashSet的容量为16,一次扩容后是容量为32 -
LinkedHashSet:继承自HashSet,是HashSet的子类,可实现元素的有序性。底层结构为hash表+链表。hash表保证元素的唯一性,链表保证元素的有序性。
-
TreeSet:底层结构为红黑树,元素按照规则进行排序。怎么制定排序规则?
1、自然排序,集合中的元素类继承Comparable接口实现compareTo方法
2、构造器排序,编写一个继承Comparator接口的类,实现compare方法,在构造TreeSet对象时作为参数传递进去。
Map:
Map通过内部类Entry封装key和value
- HashMap: 底层数据结构为内部类node类型的数组+链表+红黑树,key和value可为null,无序,线程不安全,效率高。数组中存放链表,通过hash(key)计算hash值,通过链表解决hash冲突问题,红黑树进行排序。负载因子为0.75,增量为1倍。
- HashTable: 继承自Dictionary类(被废弃了,见源代码注释中)。key和value不能为null,线程安全,但效率不高(推荐使用concurrentHashMap),其它基本同HashMap
- TreeMap: 底层结构为红黑树,无序,不允许重复,会对元素进行排序,但性能一般比前两种较差。
使用场景
那么,什么时候该用什么集合呢?
— Collection:
-
元素唯一用Set,
- 若要有序用LinkedHashSet
- 若要大小自动排序用TreeSet
- 否则用HashSet
- 不知道用啥默认情况就用HashSet
-
否则用List,
- 线程安全用Vector
- 增删多用LinkedList
- 否则用Arraylist
- 不知道用啥默认情况就用Arraylist
-
不知道用啥就用Arraylist
— Map:
- 线程安全就用ConcurrentHashMap(HashTable效率较低)
- 要有序就用LinkedHashMap
- 实现元素排序就用TreeMap
- 不知道用啥默认情况就用HashMap
注:
1、有序:
文中多次提到有序无序的概念,一种是能否保留住元素添加的顺序,如Arraylist读取元素时发现元素顺序没变;另一种是对元素按照规则进行排序,如TreeSet。
2、扩容
集合不同与数组,会自动扩容,负载因子为集合扩容的阈值,如HashMap负载因子默认为0.75,当元素个数超过16*0.75=12时HashMap即会自动扩容。集合的扩容都是新开辟空间并将原来的所有元素复制进去,底层有hash表的还需另外计算hash值,因此扩容会降低效率。
3、特性
在集合中,类的特性一般由底层数据结构决定,如底层有红黑树的,TreeSet,TreeMap则能实现排序;底层有链表的LinkedHashSet则能实现有序。