TreeMap
TreeMap基于红黑树(二叉平衡树加二叉搜索树)。
TreeMap各项操作时间复杂度是O(logn)。
TreeMap的key必须实现compareable或者传入comparable。
遍历得到的结果是有序的(中序遍历)。
HashMap
HashMap的基础是一个Entry数组。
Entry对象是HashMap的基本元素。同时Entry中有next属性,因此Entry也是一个链表。
HashMap中的Entry数组有默认的长度和装载因子,默认长度为16,装载因子为0.75。也就是说默认情况下当Entry数组的长度超过16*0.75后HashMap会执行扩容操作,容量会扩大为原来的两倍。扩容操作非常耗时,应该尽量避免。
HashMap散列的方法是:根据key获取一个hashCode,用这个hashCode和数组长度做取余运算,得到一个下标,这个下标就是存放当前Entry的下标。
当不同的key计算出相同的下标时代表发生哈希冲突,这时Entry以链表的方式存放。
LinkedHashMap
LinkedHashMap继承自HashMap。
LinkedHashMap拥有HashMap大多数特性,比如默认容量16,装载因子0.75。
LinkedHashMap内部维护了一个双向链表,并且迭代的时候遍历的是链表而不是hash表。
LinkedHashMap有一个accessOrder属性,当设置该属性为true时,插入和取出Entry时会把元素移到链表尾,可以用此来实现最近最少使用的缓存策略。
HashTable
HashTable与HashMap类似。内部都维护了hash表,用链地址法解决哈希冲突。
HashTable默认容量为11,装载因子为0.75。
HashTable容量可以是任意值,而HashMap只能是2^n。
HashTable线程安全。
HashTable扩容为原来的2倍+2。
HashMap计算索引的方式是h&(length-1),而Hashtable用的是模运算,效率上是低于HashMap的。
HashTable不允许键和值为null。
ConcurrentHashMap
用于高并发的线程安全Map,其底层和HashMap类似。
对于一个key,先进行一次hash操作,得到hash值h1,也即h1 = hash1(key);
将得到的h1的高几位进行第二次hash,得到hash值h2,也即h2 = hash2(h1高几位),通过h2能够确定该元素的放在哪个Segment;
将得到的h1进行第三次hash,得到hash值h3,也即h3 = hash3(h1),通过h3能够确定该元素放置在哪个HashEntry。
我的理解就是Segment加上HashMap组成ConcurrentHashMap。其中Segment是RentrentLock的子类,是可以加锁的。
默认Segment数量是16。可以理解为并发度。
ConcurrentHashMap是弱一致性的,有时put之后不能立即对get可见。
ArrayList
ArrayList的基础是一个Object数组。
ArrayList的默认长度为10。扩容时扩大的容量是当前容量的1.5倍。
ArrayList的向指定位置添加/删除元素是通过复制数组来实现的。
CopyOnWriteArraryList
读写分离来实现线程安全。
读操作不加锁,写操作加锁。
进行写操作的时候先复制原数组,然后对数组进行写操作,写完后array指向新的数组。
比较浪费内存。
Vector和Stack
Vector和ArrayList类似,初始容量都是10。
Vector扩容时在原容量的基础上加上装载量,若没有指定装载量,则扩容为原容量的2倍。
Vector线程安全但效率较低。
Stack继承自Vector,并拥有栈的特性。Stack也是线程安全的。
LinkedList
LinkedList内部通过双向链表实现。
LinkedList插入方便,查找费时(查找做了优化,判断位置在链表前半部分还是后半部分)。
LinkedList实现了Deque接口,可以当成栈、队列、双端队列来使用。