Java集合框架是一类用来存放元素的容器,主要分为实现了Map接口和实现了Collection接口的两类,前者存放的元素是一对key-value的映射,要求key唯一,后者存放的是单个元素,其中实现了Set接口的容器要求容器中的元素不可重复。
泛型
所谓泛型,就是类型参数话,集合框架下定义的容器希望不被局限于某一类元素,而是一套通用框架,可以存放除基本类型以为的其他类型。在集合容器变量声明时使用某一类型,那么此容器就只能存放这一类型的元素,并且容器中的元素可以调用这一类型元素可以调用的方法。
Collection类
ArrayList
ArrayList是通过数组实现的List,具有快速随机查找的特点,但是删除元素和插入元素效率较低。常用的API有:
1 | int size(); |
ArrayList实现了Cloneable接口,可以实现存储元素引用的浅拷贝,即两个容器中引用对象仍然相同,实现了Serializable接口,支持序列化和反序列化。
LinkedList
使用链表实现,每个节点item引用对象,和next,pre两个指针。LinkedList实现了Deque接口,可以从链表双端对链表进行操作。由于实现方式是链表,所以LinkedList具有插入和删除比较快,随机访问较慢的特点。LinkedList具有很多双端操作链表的API,可以认为如果不带显式的first和last方法,那么删除元素默认在链表尾部进行,添加元素在链表头部进行。
1 | private static class Node<E> { |
LinkedList不是线程安全的,如果有多个线程同时对LinkedList的结构进行修改(增加或者删除节点),有可能会导致链表出现环状。可以使用如下方法进行包装得到线程安全的List。
1 | public static <T> List<T> synchronizedList(List<T> list) |
Vector
Vector是线程安全的,有可能引起线程不安全的操作和获取相关Vector信息的值的方法都被synchronized修饰了。但是在不要求线程安全的场景下,推荐使用ArrayList代替Vector,性能更好。
Stack
Stack是继承自Vector的集合,具有后进先出的特点。
1 | public E push(E item) |
HashSet
HashSet实现了Set接口,可以保证元素的容器中元素唯一,但是不保证有序。HastSet是通过HashMap实现的,保证容器中元素唯一的方式是,每次插入的元素实际是作为(key,value)中的key,value是一个Object对象,HashMap是可以保证存入元素key是唯一的,所以HashSet能够保证容器中的元素唯一。
1 | public boolean add(E e) { |
HashSet同样是线程不安全的,如果需要在多线程场景中使用hashSet,推荐如下封装:
1 | Set s = Collections.synchronizedSet(new HashSet(...)); |
LinkedHashSet
继承自HashSet,与HashSet相同,可保证元素唯一,使用LinkedHashMap实现,可以保证插入元素顺序可知。
TreeSet
实现了SortedSet接口,可以保证容器内元素不重复,可排序。
Map类
实现了Map接口的容器类用来存放的元素是一组key到value的映射关系,LinkedHashMap继承自HashMap,可以在HashMap的基础上保证存入顺序是可知的。
HashMap
LinkedHashMap
1 | static class Entry<K,V> extends HashMap.Node<K,V> { |
LinkedHashMap实现这一功能的方式是,其中的每一个节点,都有两个指针,before和after,分别指向前一个插入节点,和后一个插入的节点。
LinkedhashMap是如何保证插入顺序有序的?重写了HashMap的newNode方法,将当前插入节点的before指针指向了插入前的尾节点。
1 | Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { |
1 | public static void main(String[] args) { |
TreeMap
基于红黑树实现的,对可对key进行排序的NavigableMap。
reference:
https://zhuanlan.zhihu.com/p/34490361