本文讲述的是Java中transient关键字的作用
前言
在阅读ArrayList和Vector源码的学习过程中,我发现存储ArrayList的元素的数组缓冲区用到了transient
关键字来进行存储优化,而Vector却没有,这是为什么呢?
一、transient
transient
关键字是开发中用的比较少的一个关键字,它在序列化和反序列化中比较重要,通常面试时会考察它的作用和它的使用场景,还有它在什么情况下会失效。transient的作用是用来防止属性被序列化
二、ArrayList中transient的作用
ArrayList
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
ArrayList中writeObject的实现
/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* 将 ArrayList 实例的状态保存到流中(即序列化它)。
* 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[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
这里ArrayList实现了writeObject方法,可以看到只会保存List的实际size个数的elementData,也就是说保存非空数组位置上的数据,并且提供了
fast-fail快速失败机制
,可以提供弱一致性。
Vector
/**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/
protected Object[] elementData;
Vectort中writeObject的实现
/**
* Save the state of the {@code Vector} instance to a stream (that
* is, serialize it).
* This method performs synchronization to ensure the consistency
* of the serialized data.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
final java.io.ObjectOutputStream.PutField fields = s.putFields();
final Object[] data;
synchronized (this) {
fields.put("capacityIncrement", capacityIncrement);
fields.put("elementCount", elementCount);
data = elementData.clone();
}
fields.put("elementData", data);
s.writeFields();
}
Vector 也实现了 writeObject 方法,但方法并没有像 ArrayList 一样进行优化存储
data = elementData.clone();
clone()的时候会把 null 值也拷贝。所以保存相同内容的 Vector 与 ArrayList, Vector 的占用的字节比 ArrayList 要多
三、区别
- ArrayList 是非同步实现的一个单线程下较为高效的数据结构(相比 Vector 来说)。 ArrayList 只通过一个修改记录字段提供弱一致性,主要用在迭代器里。没有同步方法。 即上面提到的 Fast-fail 机制.ArrayList 的存储结构定义为 transient,重写 writeObject 来实现自定义的序列化,优化了存储。
- 同步处理:Vector 同步,ArrayList 非同步 Vector 缺省情况下增长原来一倍的数组 长度,ArrayList 是 0.5 倍. ArrayList: int newCapacity = oldCapacity + (oldCapacity >> 1); ArrayList 自动扩大容量为原来的 1.5 倍(实现的时候,方法会传入一个期望的最小容量,若扩容后容量仍然小于最小容量,那么容量就为传入的最小容量。扩 容的时候使用的 Arrays.copyOf 方法最终调用 native 方法进行新数组创建和数据拷贝)。
- Vector: int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
- Vector 指定了
initialCapacity,capacityIncrement 来初始化的时候,每次增长 capacityIncrement