ArrayList
-
随机访问高效,不适合频繁更新场景;
-
动态数组,每次扩容为1.5倍;
-
add在数组末尾;
-
非线程安全,多线程中可以选择Vector或者CopyOnWriteArrayList;
LinkedList
- 双向链表,可以被当作堆栈和双端队列,适合频繁更新场景,不存在容量不足;
- 顺序访问高效,随机访问效率低效,随机访问get(i)先二分,再从前往后或从后往前找;
- add在链表尾部;
- jdk1.7和1.8同,与1.6区别在于:1.6是循环链表,在头结点操作繁琐;
- contains是从头到尾遍历寻找;
- indexOf也是从头到尾遍历寻找;
- for (Integer integ:list)这种方式遍历效率最高;
Vector
- 继承了AbstractList,是队列;
- 通过数组实现,线程安全;
Stack
- Stack是继承于Vector,也是通过数组实现的;
HashMap
- jdk1.7
- threshold= 容量 * loadFactor ,当HashMap中存储数据的数量(size)达到threshold时,就需要将HashMap的容量扩大一倍;
-
containsKey() 是先hash找到桶,然后顺着链表往后找;
-
get() 也是先hash找到桶,然后顺着链表找;
-
put() 先hash找到桶index,然后顺着链表找key是否存在,存在则新value覆盖,不存在则创建一个entry放在该桶最前边(链表头,头插法);
-
jdk1.8
- 与jdk1.7区别:
- 当桶中链表节点数大于TREEIFY_THRESHOLD时,将链表转换为红黑树;
- 当桶中红黑树节点数小于UNTREEIFY_THRESHOLD时,将红黑树转换为链表;
- 进行树化的时候还有一次判断:
- table.length > MIN_TREEIFY_CAPACITY(64),才会发生转换。这是为了避免在哈希表建立初期,多个键值对恰好被放入了同一个链表而导致不必要的转化。
- 极端情况下(都在一个桶),jdk1.7查询时间为O(n),而jdk1.8查询时间为O(logn);
-
put() 如果是链表结构,步骤同1.7,只不过是插入到链表尾部(尾插法)!
-
get() 如果是树则搜索树,是链表则遍历链表;
-
resize() 重哈希的计算方式大大简化,仅通过计算高出来的一位是1还是0进行拆分,不仅计算方式简单,而且还把之前的冲突分散到其他的桶里。
-
如果是1,则位于新数组中相同的位置+旧数组长度的位置;
-
如果是0,则位于新数组中相同的位置。
-
- 与jdk1.7区别:
Hashtable
- 数据结构同hashmap;
-
put和get同hashmap,只不过就是方法前加了synchronized;