什么是集合
集合是存放数据的容器,准确的说是存放数据对象引用的容器。
集合都是存放对象的引用,不是存放对象本身
集合类主要有三种:List、Map、Set
List(列表)
ArrayList(数组列表)
ArrayList继承自 AbstractList 类,底层通过数组实现容量动态化,对数据进行插入、删除时都需要对数组进行拷贝并且重新排序,查询快、增删慢、线程不安全、效率高。
想要使ArrayList线程安全有三种方式
1.自己写个包装类,根据业务一般是add/update/remove加锁
2.Collections.synchronizedList(new ArrayList<>()); 使用synchronized加锁
3.CopyOnWriteArrayList<>() 使用ReentrantLock加锁
ArrayList的扩容机制
JDK1.7之前默认大小是10,JDK1.7之后默认大小是0
未指定集合容量默认为10,若已指定集合大小集合大小为指定容量
当集合第一次添加元素是,扩容容量为10
ArrayList的扩容容量为1.5倍
LinkedList(双向列表)
LinkedList继承 AbstractSequentialList 类,底层通过双向链表实现,因为LinkedList同时实现了List接口和Qeque(double ended queue(双端队列))对口,所以他既可以看成一个循序容器,也可以当成一个队列,所以可以当成栈或者队列来使用。
查询慢、增删快、线程不安全、效率高。
Vector
Vector继承于 AbstractList 类,底层通过数组实现,查询快、增删慢、线程安全、效率低,Vector的扩容容量为两倍。
Stack
通过继承Vector类,Stack类可以很容易的实现他本身的功能。因为大部分的功能在Vector里面已经提供支持了。
ArrayQueue(数组队列)
ArrayQueue继承于双端队列,ArrayQueue是没有边界的,在栈的使用中ArrayQueue比Stack,LinkedList更快,ArrayQueue的线程是不安全的。
Vector、ArrayList、LinkedList的区别
ArrayList扩容之后容量增加1.5倍,Vector默认情况下扩容之后容量增加两倍,Vector可以设置容量增量而ArrayList不可以。
Map
HashMap
HashMap继承于AbstractMap,底层是哈希表是无序集合,查询速度快,可以存储null,key不可重复,重复则会被覆盖,HashMap线程不安全。
HashMap的内部数据结构在各个版本的实现中略有不同,在JDK1.7中数据结构是单链表+数组,在JDK1.8及之后数据结构是单链表+数组+红黑树
HashMap的默认长度为16,负载因子为0.75,负载因子为0.75的意思是当元素沾满map的75%时,进行扩容,扩容的长度为两倍,扩容之后重新排序。
适用于较少的线程的需求,如果线程较大可以用 ConcurrentHashMap 替代。
当数据需要映射关系是应该优先使用Map。
LinkedHashMap
LinkedHashMap继承于HashMap,他的多种操作都是建立在HashMap的操作基础上的,LinkedHashMap维护了一个Entry的双向链表,保证了Entry插入的顺序。
TreeMap
TreeMap继承于AbstractMap,底层为红黑树,默认根据Key的自然顺序排序或者根据创建Map时的Comparator进行排序。
线程不安全、key不能存null。
进行增删查时时间复杂度为O(log2 n),而HashMap的时间为O(1)
Set
HashSet
HashSet底层通过HashMap实现为无序Set,HashMap是通过链表+数组+红黑树实现的,增删查找的时间复杂度为O(1),线程不安全,元素可为null,
在使用HashSet时,所有的值都是存储在一个HashMap的Key上的。
HashSet不能存入相同元素是因为,重写了HashCode()和equals(),当先HashSet添加元素的时候,首先计算元素的HashCode值,然后通过扰动计算和按位与的方式计算出这个元素的存储位置,如果这个位置为空,就将元素添加进去,如果不为空,则用equals()方法来比较元素是否相等,先等就不添加,否则找一个空位添加。
LinkedHashSet
LinkedHashSet时HashSet的子类,底层通过LinkedHashMap实现,维护了一个数组+双向链表,和HashSet不同的是,双向链表可以维护元素的次序,因此使得LinkedHashSet有序。
SortedSet
SortedSet是一个接口,他只有TreeSet这一个实现可用,它包含的元素是在内部排序的。
TreeSet
TreeSet底层通过TreeMap实现,TreeMap是通过红黑树实现的,按元素的自然顺序排序,线程不安全,元素不可为null,时间复杂度为O(logN)
在使用TreeSet时,所有的值都是在一个TreeMap的Key上的。
TreeSet是通过compare To()来判断重复的。
Queue
Deque
Deque是双端队列的缩写,是queue的一个子类,是一个支持两端元素插入和删除操作的线性集合,可以把它当做队列来使用。
与List接口不同,该接口不支持对元素的索引访问。
ArrayDeque
ArrayDeque是Deque的一个子类,线程不安全,可以当成栈或队列来使用,效率高于Stack和LinkedList,ArrayDeque不支持null值。
Deque的元素存储在一个可变数组里,Deque的容量大小是数组的长度,数组的长度是2的幂,默认长度为16,且数组不能被填满,在被填满是立即改变大小,从而避免头尾绕城相等。
PriorityQueue
队列中除了Stack和queue还有一种特殊的队列PriorityQueue(优先队列),优先队列的作用是能让内部元素进行排序。
PriorityQueue是由二叉小顶堆实现,可以用一颗完全二叉树来表示,不可插入null元素,大小是无界的。