Java集合分析3

栈的实现其实有两种, 一种是使用Vector实现的, 一种是使用队列行数据结构实现的具体参考一下两种方式

实现方式1 线程安全的

写在前面, 在讲栈之前, 先要讲一下Vector, Vector其实是类似于ArrayList的, 其内部本身实现的方式也是使用数组存放元素,其与ArrayList不同之处在于, Vector对数组的操作是同步的, 其是一个线程安全的集合类.(方法是synchronized)

整体的代码非常简单, 注意这个栈的操作也是线程安全的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public
class Stack<E> extends Vector<E> {
/**
* Creates an empty Stack.
*/
public Stack() {
}

/**
* Pushes an item onto the top of this stack. This has exactly
* the same effect as:
* <blockquote><pre>
* addElement(item)</pre></blockquote>
*
* @param item the item to be pushed onto this stack.
* @return the <code>item</code> argument.
* @see java.util.Vector#addElement
*/
public E push(E item) {
addElement(item);

return item;
}

/**
* Removes the object at the top of this stack and returns that
* object as the value of this function.
*
* @return The object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
栈顶是数组的末尾.
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E pop() {
E obj;
int len = size();

obj = peek();
removeElementAt(len - 1);

return obj;
}

/**
* Looks at the object at the top of this stack without removing it
* from the stack.
*
* @return the object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E peek() {
int len = size();

if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}

/**
* Tests if this stack is empty.
*
* @return <code>true</code> if and only if this stack contains
* no items; <code>false</code> otherwise.
*/
public boolean empty() {
return size() == 0;
}

/**
* Returns the 1-based position where an object is on this stack.
* If the object <tt>o</tt> occurs as an item in this stack, this
* method returns the distance from the top of the stack of the
* occurrence nearest the top of the stack; the topmost item on the
* stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
* method is used to compare <tt>o</tt> to the
* items in this stack.
*
* @param o the desired object.
* @return the 1-based position from the top of the stack where
* the object is located; the return value <code>-1</code>
* indicates that the object is not on the stack.
*/
public synchronized int search(Object o) {
int i = lastIndexOf(o);

if (i >= 0) {
return size() - i;
}
return -1;
}

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1224463164541339165L;
}

实现方式2 非线程安全

我们在上一个文章中详细说明了LinkedList, 其实LinkedList也是可以做为栈使用的.参考一片文章Java 集合源码剖析, ArrayDequeLinkedListDeque的两个通用实现,由于官方更推荐使用AarryDeque用作栈和队列.

从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也就是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素。

1
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable{}

可以直接参考一下Java 集合源码剖析无非就是对数组两端的增删改查, 特殊的在于ArrayDeque实现的是循环数组.

非常经典的一个方法

1
2
3
4
5
6
7
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}

head = (head - 1) & (elements.length - 1), 这一句由于elements.length 始终是2的整数倍, 且是int类型因此

1
2
3
4
5
6
7
elements.length -1 的二进制应该是
0 xxxxxxxx 1111(初始化是16 0-15)
因此首次head -1 = -1 (1的反码+1 就是-1)
因该是(补码)
111111111111111
与上面的按位与被置为整数15 (保留低位4位)
下一次
1
2
3
4
5
6
7
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}