From 61e1a609ddae770a514c7e62e3332f18139de312 Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Fri, 15 Jun 2018 14:26:33 +0800 Subject: [PATCH] auto commit --- notes/Java 容器.md | 77 ++++++------------ pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png | Bin 0 -> 6144 bytes 2 files changed, 24 insertions(+), 53 deletions(-) create mode 100644 pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png diff --git a/notes/Java 容器.md b/notes/Java 容器.md index b34caa09..2d070ff4 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -11,8 +11,6 @@ * [LinkedList](#linkedlist) * [HashMap](#hashmap) * [ConcurrentHashMap](#concurrenthashmap) - * [LinkedHashMap](#linkedhashmap) - * [TreeMap](#treemap) * [参考资料](#参考资料) @@ -102,16 +100,12 @@ List list = Arrays.asList(1,2,3); # 三、源码分析 -建议先阅读 [算法-查找](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E7%AE%97%E6%B3%95.md#%E6%9F%A5%E6%89%BE) 部分,对容器类源码的理解有很大帮助。 +如果没有特别说明,以下源码分析基于 JDK 1.8。 -至于 ConcurrentHashMap 的理解,需要有并发方面的知识,建议先阅读:[Java 并发](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Java%20%E5%B9%B6%E5%8F%91.md) - -以下源码从 JDK 1.8 提取而来,下载地址:[JDK-Source-Code](https://github.com/CyC2018/JDK-Source-Code)。 +在 IDEA 中 double shift 调出 Search EveryWhere,查找源码文件,找到之后就可以阅读源码。 ## ArrayList -[ArrayList.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/ArrayList.java) - ### 1. 概览 实现了 RandomAccess 接口,因此支持随机访问,这是理所当然的,因为 ArrayList 是基于数组实现的。 @@ -139,7 +133,7 @@ transient Object[] elementData; // non-private to simplify nested class access 添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够时,需要使用 grow() 方法进行扩容,新容量的大小为 `oldCapacity + (oldCapacity >> 1)`,也就是旧容量的 1.5 倍。 -扩容操作需要调用 `Arrays.copyOf()` 把原数组整个复制到新数组中,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。 +扩容操作需要调用 `Arrays.copyOf()` 把原数组整个复制到新数组中,这个操作代价很高,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。 ```java public boolean add(E e) { @@ -152,13 +146,11 @@ private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } - ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; - // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); @@ -179,20 +171,17 @@ private void grow(int minCapacity) { ### 4. 删除元素 -需要调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上,复制的代价很高。 +需要调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上。 ```java public E remove(int index) { rangeCheck(index); - modCount++; E oldValue = elementData(index); - int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work - return oldValue; } ``` @@ -226,8 +215,6 @@ private void writeObject(java.io.ObjectOutputStream s) ## Vector -[Vector.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/Vector.java) - ### 1. 同步 它的实现与 ArrayList 类似,但是使用了 synchronized 进行同步。 @@ -250,26 +237,26 @@ public synchronized E get(int index) { ### 2. ArrayList 与 Vector -- Vector 和 ArrayList 几乎是完全相同的,唯一的区别在于 Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector,因为同步操作完全可以由程序员自己来控制; +- Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector,因为同步操作完全可以由程序员自己来控制; - Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。 ### 3. Vector 替代方案 -为了获得线程安全的 ArrayList,可以使用 Collections.synchronizedList(); 得到一个线程安全的 ArrayList,也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类; +为了获得线程安全的 ArrayList,可以使用 `Collections.synchronizedList();` 得到一个线程安全的 ArrayList。 ```java List list = new ArrayList<>(); List synList = Collections.synchronizedList(list); ``` +也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。 + ```java -List list = new CopyOnWriteArrayList(); +List list = new CopyOnWriteArrayList<>(); ``` ## LinkedList -[LinkedList.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/LinkedList.java) - ### 1. 概览 基于双向链表实现,内部使用 Node 来存储链表节点信息。 @@ -289,7 +276,7 @@ transient Node first; transient Node last; ``` -

+

### 2. ArrayList 与 LinkedList @@ -299,19 +286,17 @@ transient Node last; ## HashMap -[HashMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/HashMap.java) - -为了便于理解,以下内容以 JDK 1.7 为主。 +为了便于理解,以下源码分析以 JDK 1.7 为主。 ### 1. 存储结构 -使用拉链法来解决冲突,内部包含了一个 Entry 类型的数组 table,数组中的每个位置被当成一个桶。 +内部包含了一个 Entry 类型的数组 table。 ```java transient Entry[] table; ``` -其中,Entry 就是存储数据的键值对,它包含了四个字段。从 next 字段我们可以看出 Entry 是一个链表,即每个桶会存放一个链表。 +其中,Entry 就是存储数据的键值对,它包含了四个字段。从 next 字段我们可以看出 Entry 是一个链表,即数组中的每个位置被当成一个桶,一个桶存放一个链表,链表中存放哈希值相同的 Entry。也就是说,HashMap 使用拉链法来解决冲突。

@@ -437,7 +422,7 @@ public V put(K key, V value) { } ``` -HashMap 允许插入键位 null 的键值对,因为无法调用 null 的 hashCode(),也就无法确定该键值对的桶下标,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。 +HashMap 允许插入键为 null 的键值对。因为无法调用 null 的 hashCode(),也就无法确定该键值对的桶下标,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。 ```java private V putForNullKey(V value) { @@ -544,9 +529,9 @@ y : 10110010 y%x : 00000010 ``` -我们知道,位运算的代价比求模运算小的多,因此在进行这种计算时能用位运算的话能带来更高的性能。 +我们知道,位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能。 -确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的幂次方,那么就可以将这个操作转换为位运算。 +确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。 ```java static int indexFor(int h, int length) { @@ -564,10 +549,10 @@ static int indexFor(int h, int length) { | 参数 | 含义 | | :--: | :-- | -| capacity | table 的容量大小,默认为 16,需要注意的是 capacity 必须保证为 2 的次方。| +| capacity | table 的容量大小,默认为 16,需要注意的是 capacity 必须保证为 2 的 n 次方。| | size | table 的实际使用量。 | | threshold | size 的临界值,size 必须小于 threshold,如果大于等于,就必须进行扩容操作。 | -| load_factor | table 能够使用的比例,threshold = capacity * load_factor。| +| load_factor | 装载因子,table 能够使用的比例,threshold = capacity * load_factor。| ```java static final int DEFAULT_INITIAL_CAPACITY = 16; @@ -608,7 +593,6 @@ void resize(int newCapacity) { threshold = Integer.MAX_VALUE; return; } - Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; @@ -645,11 +629,11 @@ capacity : 00010000 new capacity : 00100000 ``` -对于一个 Key,它的 hash 如果在第 6 位上为 0,那么取模得到的结果和之前一样;如果为 1,那么得到的结果为原来的结果 + 8。 +对于一个 Key,它的哈希值如果在第 6 位上为 0,那么取模得到的结果和之前一样;如果为 1,那么得到的结果为原来的结果 + 8。 ### 7. 扩容-计算数组容量 -HashMap 构造函数允许用户传入的容量不是 2 的幂次方,因为它可以自动地将传入的容量转换为 2 的幂次方。 +HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它可以自动地将传入的容量转换为 2 的 n 次方。 先考虑如何求一个数的掩码,对于 10010000,它的掩码为 11111111,可以使用以下方法得到: @@ -659,7 +643,7 @@ mask |= mask >> 2 11111100 mask |= mask >> 4 11111111 ``` -mask+1 是大于原始数字的最小的 2 幂次方。 +mask+1 是大于原始数字的最小的 2 的 n 次方。 ``` num 10010000 @@ -682,20 +666,17 @@ static final int tableSizeFor(int cap) { ### 8. 链表转红黑树 -应该注意到,从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。 +从 JDK 1.8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。 ### 9. HashMap 与 HashTable -- HashTable 是同步的,它使用了 synchronized 来进行同步。它也是线程安全的,多个线程可以共享同一个 HashTable。HashMap 不是同步的,但是可以使用 ConcurrentHashMap,它是 HashTable 的替代,而且比 HashTable 可扩展性更好。 +- HashTable 使用 synchronized 来进行同步。 - HashMap 可以插入键为 null 的 Entry。 -- HashMap 的迭代器是 fail-fast 迭代器,而 Hashtable 的 enumerator 迭代器不是 fail-fast 的。 -- 由于 Hashtable 是线程安全的也是 synchronized,所以在单线程环境下它比 HashMap 要慢。 +- HashMap 的迭代器是 fail-fast 迭代器。 - HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。 ## ConcurrentHashMap -[ConcurrentHashMap.java](https://github.com/CyC2018/JDK-Source-Code/blob/master/src/1.7/ConcurrentHashMap.java) - ### 1. 存储结构 ```java @@ -819,22 +800,12 @@ public int size() { ### 3. JDK 1.8 的改动 -[ConcurrentHashMap.java](https://github.com/CyC2018/JDK-Source-Code/blob/master/src/ConcurrentHashMap.java) - JDK 1.7 使用分段锁机制来实现并发更新操作,核心类为 Segment,它继承自重入锁 ReentrantLock,并发程度与 Segment 数量相等。 JDK 1.8 使用了 CAS 操作来支持更高的并发度,在 CAS 操作失败时使用内置锁 synchronized。 并且 JDK 1.8 的实现也在链表过长时会转换为红黑树。 -## LinkedHashMap - -[LinkedHashMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/HashMap.java) - -## TreeMap - -[TreeMap.java](https://github.com/CyC2018/JDK-Source-Code/tree/master/src/TreeMap.java) - # 参考资料 - Eckel B. Java 编程思想 [M]. 机械工业出版社, 2002. diff --git a/pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png b/pics/5158bc2f-83a6-4351-817e-c9b07f955d76.png new file mode 100644 index 0000000000000000000000000000000000000000..61f0adceabc1c810d7799b2a6e62a8d016a28c13 GIT binary patch literal 6144 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