参考:
http://www.jianshu.com/p/ca06a33f143c
http://brokendreams.iteye.com/blog/1918475
先看allocateElements函数
-
-
-
-
-
-
private void allocateElements(int numElements) {
-
int initialCapacity = MIN_INITIAL_CAPACITY;
-
-
-
if (numElements >= initialCapacity) {
-
initialCapacity = numElements;
-
initialCapacity |= (initialCapacity >>> 1);
-
initialCapacity |= (initialCapacity >>> 2);
-
initialCapacity |= (initialCapacity >>> 4);
-
initialCapacity |= (initialCapacity >>> 8);
-
initialCapacity |= (initialCapacity >>> 16);
-
initialCapacity++;
-
-
if (initialCapacity < 0)
-
initialCapacity >>>= 1;
-
}
-
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博客 ” ,链接:https://blog.itpub.net/29254281/viewspace-2126289/
,如需转载,请注明出处,否则将追究法律责任。