Java 集合框架容器
Java 集合框架主要包括两种类型的接口容器
- collection,存储元素集合
- map,存储键值对
一、Collection 接口的三个子类型
List、Set 和 Queue,工作中比较常用的就是 List 和 Set
- List:存储的数据是有序的,可重复的
- Set:存储的数据是无序的,不可重复的,数据具有唯一性
1、List 接口下的数据结构
- ArrayList:Object[] 数组
- Vector:Object[] 数组
- LindedList:双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
2、Set 接口下的数据结构
- HashSet:无序的,不能重复的,数据具有唯一性,可以存入空数据
- TreeSet:有序的,不能重复的,数据具有唯一性,不能写入空数据
- LinkedHashSet:有序的,不能重复的,数据具有唯一性,可以写入空数据
二、Map 接口
Map 使用键值对的形式来存储数据(key-value),每个 key 只能对应一个 value
key 是无序的,不可以重复的
value 是无序的,可以重复的
1、HashMap
HashMap 在 JDK1.8时,对它的底层实现进行了优化,引入了红黑树的数据结构和扩容的优化
HashMap:
- 根据 hashCode值来存储数据,大多数情况下可以直接定位到它的值,因此访问速度非常快,但是遍历的.顺序是不确定的。
- 只允许一条数据的键为 null ,允许多条数据的值为 null。
- HashMap 是非线程安全的,因为同一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致,如果需要实现线程安全的话,可以用 Collections 的 synchronizedMap 对 HashMap 进行包装,也可以直接使用 concurrentHashMap。
- HashMap 是无序的。
2、HashTable
HashTable 很多映射的常用功能与 HashMap 相似,不同的是 HashTable 继承的是 Dictionary 类。
- HashTable 是线程安全的,任一时间只有一个线程能写 HashTable,并发性不如 ConcurrentHashMap,因为 ConcurrentHashMap 引入了分段锁,所以不建议使用 HashTable。
- 如果不需要线程安全的场合可以使用 HashMap,需要线程安全的话可以使用 ConcurrentHashMap。
3、LinkedHashMap
LinkedHashMap 是 HashMap 的一个子类,保存了记录的插入顺序,在用 iterator 进行遍历的时候,先得到的记录肯定是先插入的,也可以在构造时带参数,按照插入顺序排序。
- LinkedHashMap 是有序的。
- LinkedHashMap 是线程不安全的。
4、TreeMap
TreeMap 是基于红黑树来实现
- TreeMap 实现了 SortedMap 接口,能够把保存的记录根据键来排序,默认按照键值进行升序排序,也可以指定排序的比较器。
- TreeMap 实现了 Cloneable 接口, 意味着它可以被克隆。
- TreeMap 实现了 Serializable 接口,意味这个它可以被序列化。
三、各容器之间的比较
1、ArrayList 与 Vector
相同点
- 都实现 List。
- 底层都是通过数组来实现的。
不同点
3. Vector 是线程安全的,类中的方法都是用 synchronized 进行修饰的,ArrayList 是非线程安全的。
4. Vector 是遗留类,这意味着它不完全支持集合框架,而 ArrayList 不是遗留类。
5. ArrayList 在底层数组不够用的时候会在原来的基础上扩展0.5倍, 而 Vector 会扩展 1倍。
6. Vector 有扩展因子,所以每次可以指定扩展的容量,而 ArrayList 没有,ArrayList有两个属性,存储数据的数组 elementData,存储记录条数的 size,Vector 有三个属性,存储数据的数组 elementData,存储记录条数的 elementCount,还有一个扩展数组大小的扩展因子 capacityIncrement。
2、ArrayList 与 LinkedList
相同点
- 都实现 List。
- LinkedList 和 ArrayList 都是不同步的,非线程安全的
不同点
- ArrayList 底层是 Object 数组,LinkedList 使用的是双向链表。
- ArrayList 对随机访问数据 get 和 set 占据优势,因为 LinkedList 需要移动指针,需要对链表进行遍历,但是对于数据的添加和删除效率比较高,只需要改变指针指向,而 ArrayList 需要移动数据。
3、HashMap 和 HashTable
相同点
- 都实现 Map。
- 都是通过键值对形式来存储数据。
不同点
- HashMap 是非线程安全的,HashTable 是线程安全的,因为 HashTable 内部的方法都经过 synchronized 进行修饰。
- 因为线程安全的原因,HashMap 比HashTable 的效率要高。
- HashMap 可以允许 key 和 value 也可以为空,但 key 只能一次为空,null 作为值可以有多个,而 HashTable 则不允许 key 和value 为空,否则会报空指针异常。
- HashTable 初始容量为 11,每次扩容大小为原来的 2n+1,HashMap 初始容量为 16,每次扩容大小为原来的2倍。
- 底层数据结构,JDK1.8之后,HashMap 的链表长度大于阈值时,会变成红黑树(转变之前会判断数组长度,如果小于64,会先将数组进行扩容),HashTable 没有这种机制。
- HashTable 集成 Dictionary。
4、HashMap 和 HashSet
- HashMap 实现 Map 接口, HashSet 实现 Set 接口。
- HashMap 通过键值对形式来存储数据,HashSet 存储对象。
- HashMap 使用 put 方法添加数据, HashSet 使用 add 方法添加数据。
- HashMap 使用 key 来计算 HashCode,HashSet 使用 成员对象来计算 HashCode,所以可以通过 equals 来判断对象是否相等。
5、HashMap 和 TreeMap
- HashMap 和 TreeMap 都是继承 AbstractMap,但是 TreeMap 还是实现了 NavigbleMap 和 SortedMap 接口。
- 实现 NavigableMap 让 TreeMap 有了元素搜索的能力。
- 实现 SortedMap 让 TreeMap 有了对集合中元素根据键排序的能力,默认按照 key 进行升序排序,也可以自己指定排序的比较器。