持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
Collection下的集合
List 集合:
ArrayList() 是有序的动态数组列表,只能装载包装类(Integer、String、Double、Object等),允许为null和重复元素,特点:查询快、增加、删除慢
Arrraylist扩容机制
- 使用
ArrayList()构造函数时,会构造一个长度为0的数组,是一个Object数组. ArrayList(int initalCapacity)会使用指定容量的数组public ArrayList(Collection <? extends E> c)会使用集合c的大小作为数组容量add(Object o)首次扩容为10,再次扩容为上次容量的1.5倍(0.5 采用的是右移运算)且只针对初始容量为0的数组,每次扩容1.5倍的大小依次为:[0、10、15、22、33、49、73、109、163、244、366、549、823、1234、1851、2776]addAll(Collection c)没有元素时,扩容为Math.max(10,实际元素的个数),有元素时为Math.max(原始容量的1.5倍,实际元素的个数)
fail-fast与fail-safe
ArrayList是fail-fast的典型代表,遍历的同时不能修改,会报异常,尽快失败CopyOnWriteArrayList是fail-safe的典型代表,遍历时可以修改,原理是读写分离
LinkedList 与ArrayList区别:
-
ArrayList底层基于动态数组实现的,LinkedList底层基于双向链表实现的 -
访问:对于随机访问,(get/set访问)
ArrayList实现了 **RandomAccess**接口,可以直接定位到数组对应下标节点,而LinkedList需要从头节点或者尾节点开始遍历直到找到目标元素,所以:Arraylist访问速率 >LinkedList访问速率 -
插入和删除:
- 随机插入和删除:
ArrayList需要移动目标后面的节点(使用System.arrarcopy移动节点),而LinkedList只需要修改目标节点的next或者prev,所以:ArrayList随机插入删除效率 <LinkedList随机插入和删除效率 - 顺序插入和删除:
ArrayList不需要移动节点,ArrayLists顺序插入效率>LinkedList顺序插入和删除,大多数情况使用ArrayList,因为大多数情况都是顺序插入 - 头尾插入删除:
ArrayList尾部插入、删除性能高,但是部分插入需要移动元素,性能低。LinkedList头部、尾部插入删除性能高
- 随机插入和删除:
-
线程安全:LinkedList和ArrayList线程均不安全
Map下的集合
HashMap的面试题
- JDK1.7:HashMap底层为数组+链表
- JDK1.8:HashMap底层为数组+链表+红黑树
为何用红黑树,何时为转化为红黑树,为什么树化的阈值为8?
- 红黑树用来避免Dos攻击,防止链表超长,性能下降
- 当链表长度>8,并且数组容量>=64,会转化为红黑树
- hash采用泊松分布,在负载因子0.75的情况下,长度超过8,链表出现的概率最小,选择8是为了让树化几率足够小
索引如何计算?HashCode有了,为什么要二次哈希?数组容量为什么为2的n次幂?
- 先计算对象的hashcode(),在调用HashMap的hash()方法进行二次哈希,最后&(capacity-1)得到索引
- 二次哈希是为了让哈希分布更均匀
- 计算索引时,如果是2的n次幂可以使用按位与运算代替取模运算,效率更高
HashMap与HashTable不同
- 版本不同:Hashtable出生于JDK1.0,HashMap出生于JDK1.2
- 继承不同:HashMap继承AbstractMap(AbstractMap实现了Map接口),Hashtable继承Dictonary
- 线程安全:Hashtable大部分普通方法都是synchronized修饰的,是线程安全,HashMap实现从不安全的
- Key---Value:Hashtable的key、value都不能为null,源码:
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode(); //此时key为空也会报NullPointerException()
- Key---Value:HashMap的Key、Value都可以为空,计算Hash有判断,如果Key==null,则hash==0,且Value是否为不做判断
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
- 初始容量不同:Hashtable 的初始长度是 11,之后每次扩充容量变为之前的 2n+1(n 为上一次的长度)而 HashMap 的初始长度为 16,之后每次扩充变为原来的两倍