JDK7集合框架原始碼學習-ArrayDeque
參考:
http://brokendreams.iteye.com/blog/1918475
先看allocateElements函式
他主要是給定一個值numElements,如果大於預設值,則找一個大於numElements的最小的2的平方值.
他擴充套件的序列是 8,16,32,64,128...
如果numElements為17,則擴充套件為32.
轉載:
前面幾句很好理解,如果numElements太小,那麼佇列長度就取預設初始化長度;
後面一坨程式碼的意思:如果numElements大於預設初始化長度,就取最小的n使得:n = 2^k(k為整數), 且n > numElements。
求n的方法有很多:從小到大列舉k、二分k等等;可能作者覺得這些方法都太low了,又熟練掌握二進位制運算技巧,於是才有了這幾行程式碼。
下面簡單分析一下程式碼的運算過程,注:">>>"代表按位右移:
假設a=1xxxxxxxxxxxx...(base 2, x代表該位任意為0或1)
首先a |= (a >>> 1)之後,a => 11xxxxxxxx...(最高兩位是1)
然後a |= (a>>> 2): a => 1111xxxxxxxxx...(最高四位是1)
再a |= (a>>> 4): a => 11111111xxxxxxx...(最高八位是1)
........
最終,a的所有低位也都變成了1,即11111111...111(全是1)
再a++ 就變成了10000000000...000(加一之後進位,比原來的二進位制串多了一位,且第一位是1,其它位都是0),這個演算法不僅時間效率高,而且只用到了一個變數,真可謂是短小精悍,在HashMap裡也可以看到這個演算法的身影。
結果:
10001(initialCapacity)
1000(移位)
11001(initialCapacity)
110(移位)
11111(initialCapacity)
1(移位)
11111(initialCapacity)
0(移位)
11111(initialCapacity)
0(移位)
32
也就是說,以17為例(二進位制10001),他會將二進位制數字補全為 11111 最後再加一.
也就是 100000,轉為十進位制數字就是32.
再看addFirst函式和addLast函式
初始化的時候,head和tail都是0
(elements.length - 1)在未擴充套件的時候,應該是一個固定值.(7,15,31,63...)
一旦容量不夠,則擴充套件一倍.
以預設的8個位置為例,雙倍擴充套件之前的資料假設為
5,6,7,8,4,3,2,1
addFirst 1-4
addLast 4-8
這時候擴充套件為16個位置,陣列位置為
4,3,2,1,5,6,7,8,null,null....
http://brokendreams.iteye.com/blog/1918475
先看allocateElements函式
- /**
- * Allocate empty array to hold the given number of elements.
- *
- * @param numElements the number of elements to hold
- */
- private void allocateElements(int numElements) {
- int initialCapacity = MIN_INITIAL_CAPACITY;
- // Find the best power of two to hold elements.
- // Tests "<=" because arrays aren't kept full.
- if (numElements >= initialCapacity) {
- initialCapacity = numElements;
- initialCapacity |= (initialCapacity >>> 1);
- initialCapacity |= (initialCapacity >>> 2);
- initialCapacity |= (initialCapacity >>> 4);
- initialCapacity |= (initialCapacity >>> 8);
- initialCapacity |= (initialCapacity >>> 16);
- initialCapacity++;
- if (initialCapacity < 0) // Too many elements, must back off
- initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
- }
- elements = (E[]) new Object[initialCapacity];
-
}
他主要是給定一個值numElements,如果大於預設值,則找一個大於numElements的最小的2的平方值.
他擴充套件的序列是 8,16,32,64,128...
如果numElements為17,則擴充套件為32.
轉載:
前面幾句很好理解,如果numElements太小,那麼佇列長度就取預設初始化長度;
後面一坨程式碼的意思:如果numElements大於預設初始化長度,就取最小的n使得:n = 2^k(k為整數), 且n > numElements。
求n的方法有很多:從小到大列舉k、二分k等等;可能作者覺得這些方法都太low了,又熟練掌握二進位制運算技巧,於是才有了這幾行程式碼。
下面簡單分析一下程式碼的運算過程,注:">>>"代表按位右移:
假設a=1xxxxxxxxxxxx...(base 2, x代表該位任意為0或1)
首先a |= (a >>> 1)之後,a => 11xxxxxxxx...(最高兩位是1)
然後a |= (a>>> 2): a => 1111xxxxxxxxx...(最高四位是1)
再a |= (a>>> 4): a => 11111111xxxxxxx...(最高八位是1)
........
最終,a的所有低位也都變成了1,即11111111...111(全是1)
再a++ 就變成了10000000000...000(加一之後進位,比原來的二進位制串多了一位,且第一位是1,其它位都是0),這個演算法不僅時間效率高,而且只用到了一個變數,真可謂是短小精悍,在HashMap裡也可以看到這個演算法的身影。
-
public static void main(String[] args) {
-
int initialCapacity = 17;
-
-
System.out.println(Integer.toBinaryString(initialCapacity)+"(initialCapacity)");
-
System.out.println(Integer.toBinaryString(initialCapacity>>>1)+"(移位)");
-
initialCapacity |= (initialCapacity >>> 1);
-
-
System.out.println(Integer.toBinaryString(initialCapacity)+"(initialCapacity)");
-
System.out.println(Integer.toBinaryString(initialCapacity>>>2)+"(移位)");
-
initialCapacity |= (initialCapacity >>> 2);
-
-
System.out.println(Integer.toBinaryString(initialCapacity)+"(initialCapacity)");
-
System.out.println(Integer.toBinaryString(initialCapacity>>>4)+"(移位)");
-
initialCapacity |= (initialCapacity >>> 4);
-
-
System.out.println(Integer.toBinaryString(initialCapacity)+"(initialCapacity)");
-
System.out.println(Integer.toBinaryString(initialCapacity>>>8)+"(移位)");
-
initialCapacity |= (initialCapacity >>> 8);
-
-
System.out.println(Integer.toBinaryString(initialCapacity)+"(initialCapacity)");
-
System.out.println(Integer.toBinaryString(initialCapacity>>>16)+"(移位)");
-
initialCapacity |= (initialCapacity >>> 16);
-
-
initialCapacity++;
-
System.out.println(initialCapacity);
- }
結果:
10001(initialCapacity)
1000(移位)
11001(initialCapacity)
110(移位)
11111(initialCapacity)
1(移位)
11111(initialCapacity)
0(移位)
11111(initialCapacity)
0(移位)
32
也就是說,以17為例(二進位制10001),他會將二進位制數字補全為 11111 最後再加一.
也就是 100000,轉為十進位制數字就是32.
再看addFirst函式和addLast函式
-
public void addFirst(E e) {
-
if (e == null)
-
throw new NullPointerException();
-
elements[head = (head - 1) & (elements.length - 1)] = e;
-
if (head == tail)
-
doubleCapacity();
- }
-
-
public void addLast(E e) {
-
if (e == null)
-
throw new NullPointerException();
-
elements[tail] = e;
-
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
-
doubleCapacity();
- }
初始化的時候,head和tail都是0
(elements.length - 1)在未擴充套件的時候,應該是一個固定值.(7,15,31,63...)
一旦容量不夠,則擴充套件一倍.
-
private void doubleCapacity() {
-
assert head == tail;
-
int p = head;
-
int n = elements.length;
-
int r = n - p; // number of elements to the right of p
-
int newCapacity = n << 1;
-
if (newCapacity < 0)
-
throw new IllegalStateException("Sorry, deque too big");
-
Object[] a = new Object[newCapacity];
-
System.arraycopy(elements, p, a, 0, r);
-
System.arraycopy(elements, 0, a, r, p);
-
elements = (E[])a;
-
head = 0;
-
tail = n;
- }
以預設的8個位置為例,雙倍擴充套件之前的資料假設為
5,6,7,8,4,3,2,1
addFirst 1-4
addLast 4-8
這時候擴充套件為16個位置,陣列位置為
4,3,2,1,5,6,7,8,null,null....
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2126289/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java集合框架原始碼剖析:ArrayDequeJava框架原始碼
- JDK7集合框架原始碼學習-ArrayList(0)JDK框架原始碼
- JDK7集合框架原始碼學習-ArrayList(1)JDK框架原始碼
- JDK7集合框架原始碼學習-ArrayList(4)SubListJDK框架原始碼
- JDK7集合框架原始碼學習-ArrayList(3)迭代器JDK框架原始碼
- JDK7集合框架原始碼學習-ArrayList(2)迭代器JDK框架原始碼
- 【Java原始碼】集合類-ArrayDequeJava原始碼
- 集合框架原始碼學習之ArrayList框架原始碼
- 集合框架原始碼學習之LinkedList框架原始碼
- 集合框架原始碼學習之HashMap(JDK1.8)框架原始碼HashMapJDK
- Java集合原始碼學習(2)ArrayListJava原始碼
- Java集合原始碼學習(1)介面Java原始碼
- Java集合原始碼學習(4)HashSetJava原始碼
- Java集合原始碼學習(5)HashMapJava原始碼HashMap
- Okio 框架原始碼學習框架原始碼
- 【Java集合原始碼剖析】Java集合框架Java原始碼框架
- Java集合框架學習Java框架
- JAVA集合:常見Set原始碼學習Java原始碼
- Java集合原始碼學習(3)LinkedListJava原始碼
- Java 集合框架------ArrayList原始碼分析Java框架原始碼
- Java 集合框架 ArrayList 原始碼剖析Java框架原始碼
- 原始碼|jdk原始碼之棧、佇列及ArrayDeque分析原始碼JDK佇列
- 集合框架-ArrayList集合的toString()方法原始碼解析框架原始碼
- 集合框架-HashSet集合的add()方法的原始碼框架原始碼
- 集合框架學習之List介面框架
- Java 容器原始碼分析之 Deque 與 ArrayDequeJava原始碼
- Java集合框架之 Java HashMap 原始碼解析Java框架HashMap原始碼
- Java集合框架原始碼剖析:TreeSet 和 TreeMapJava框架原始碼
- Java集合框架原始碼剖析:HashSet 和 HashMapJava框架原始碼HashMap
- Java 集合框架 HashSet 和 HashMap 原始碼剖析Java框架HashMap原始碼
- ArrayDeque(JDK雙端佇列)原始碼深度剖析JDK佇列原始碼
- 新一代web框架Koa原始碼學習Web框架原始碼
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼一原始碼框架筆記MySql
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼二原始碼框架筆記MySql
- 雲端計算學習路線原始碼框架筆記:Mysql原始碼三原始碼框架筆記MySql
- redis原始碼分析(六)、redis命令學習總結—Redis 集合(Set)Redis原始碼
- 集合框架-TreeSet的add()方法的原始碼解析框架原始碼
- Java集合框架原始碼剖析:LinkedHashSet 和 LinkedHashMapJava框架原始碼HashMap