集合 性能 默认容量 空时的大小 10K条目的开销(没有考虑键和值的大小) 准确设置大小? 扩展算法
HashSet O(1) 16 144 360K 否 x2
HashMap O(1) 16 128 360K 否 x2
Hashtable O(1) 11 104 360K 否 x2+1
LinkedList O(n) 1 48 240K 是 +1
ArrayList O(n) 10 88 40K 否 x1.5
StringBufferO(1) 16 72 24 否 x2
Java集合类最重要的三个接口
List,Queue,Set,Map,其中List和Set继承于Collection。
还有两个抽象类:
Collection(非有序,允许重复)
List(有序,允许重复)【ArrayList、LinkedList、Vector】
CopyOnWriteArrayList是ArrayList 的一个线程安全的变体。
Set(非有序,除了TreeSet【二叉排序树】,不允许重复)【HashSet(哈希表散列表)、TreeSet】
CopyOnWriteArraySet是HashSet的一个线程安全的变体。
Map(非有序,除了TreeMap【二叉排序树】,key不允许重复,value允许重复)【HashMap(哈希表散列表)、TreeMap】
HashTable和Vector线程安全,性能HashMap和ArrayList更好,但不是线程安全的。
HashTable不允许value为空。
ConcurrentHashMap通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍
HashMap和WeakHashMap的区别:
强引用、弱引用和动态回收内存
弱引用动态回收
(01) 新建WeakHashMap,将“键值对”添加到WeakHashMap中。
将“键值对”添加到WeakHashMap中时,添加的键都是弱键。
实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。
(02) 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到queue队列中。
例如,当我们在将“弱键”key添加到WeakHashMap之后;后来将key设为null。这时,便没有外部外部对象再引用该了key。
接着,当Java虚拟机的GC回收内存时,会回收key的相关内存;同时,将key添加到queue队列中。
(03) 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的“弱键”;同步它们,就是删除table中被GC回收的“弱键”对应的键值对。
例如,当我们“读取WeakHashMap中的元素或获取WeakReference的大小时”,它会先同步table和queue,目的是“删除table中被GC回收的‘弱键’对应的键值对”。删除的方法就是逐个比较“table中元素的‘键’和queue中的‘键’”,若它们相当,则删除“table中的该键值对”。
集合类排序Comparable和Comparator
调用java.util.Collections.sort(List list)时,List的每个对象都必须实现了comparable接口。
而Comparator接口可以通过 java.util.Collections.sort(List list,Comparator c)调用
ArrayList和Vector扩容区别
ArrayList
public void ensureCapacity(int minCapacity) {
modCount++;//父类中的属性,记录集合变化次数
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {//扩容的条件,数组需要的长度要大于实际长度
Object oldData[] = elementData;
int newCapacity = ((oldCapacity * 3)/2 + 1<minCapacity?minCapacity: ((oldCapacity * 3)/2 + 1);
elementData = (E[])new Object[newCapacity];
System.arraycopy(oldData, 0, elementData, 0, size);
}
}
Vector
public synchronized void ensureCapacity(int minCapacity) {
modCount++;//父类中的属性,记录集合变化次数
ensureCapacityHelper(minCapacity);
}
private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {//扩容的条件,数组需要的长度要大于实际长度
Object[] oldData = elementData;
//扩容因子大于0,相加,否则两倍
int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = new Object[newCapacity];
System.arraycopy(oldData, 0, elementData, 0, elementCount);
}
}
ArrayList 和LinkedList的区别:
- 底层数据结构不同:数组和双向链表
- 适用场景不同:下标随机访问和大量插入移动修改
- 扩容策略不同:*1.5 和 +1
HashMap和LinkedHashMap的区别:
- 底层数据结构不相同:HashMap=>数组+链表/红黑树;TreeMap;LinkedHashMap继承自HashMap,额外有个双向链表记录迭代顺序。
- 迭代顺序:HashMap迭代顺序和数组下标有关;LinkedHashMap默认插入顺序,还可以是访问顺序。
HashMap和TreeMap的区别:
- 底层数据结构:HashMap=>数组+链表/红黑树,TreeMap=>红黑树
- HashMap 随机访问要比TreeMap快,TreeMap的查值通过红黑树遍历,和树的高度有关。
- 都是线程不安全
HashMap、HashTable和ConcurrentHashMap的区别:
- HashMap线程不安全;HashTable线程安全,但是锁级别是对象;ConcurrentHashMap线程安全,但是锁级别是分段加锁,锁粒度减小,提高并发。
- ConcurrentHashMap利用final减少加锁需求,利用Volatile保证读写可见性。
- 扩容方式不相同。