Java 容器源码分析之 ArrayList(9)
 
- UID
- 1066743
|

Java 容器源码分析之 ArrayList(9)
序列化前面提到过数组 elementData 是使用 transient 来修饰的,这个其实就和序列化及反序列化相关。transient 是一个关键字,用 transient 修饰的变量不再是对象持久化的一部分,即默认序列化机制中该变量不用被序列化。
这一点可能让人很费解,如果不用被序列化,那么反序列化的时候不是就丢失了存储的数据了吗?实际上,在 ArrayList 中对序列化和反序列化过程进行了更细致的控制,即通过 writeObject()和 readObject() 方法。
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
| /**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/**
* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a = s.readObject();
}
}
}
| 可见,在序列化时并不是将整个数组全部写入输出流中,因为数组通常都不是处于完全填充的状态,对于为 null 的元素就不必保存,也可以达到节约空间的目的。后面我们会看到很多集合类中都采取了这种方式进行序列化和反序列化。
小结本文通过源码分析了Java 8 集合框架中ArrayList的实现方式。ArrayList内部是通过数组进行实现的,具有高效的随机访问的特性;但插入和删除元素时往往需要复制数组,开销较大。在容器创建完成后需要进行大量访问,但插入和删除操作使用较少的情况下比较适合使用ArrayList。 |
|
|
|
|
|