一,简介
修饰变量,用于标明该变量不用序列化到字节流中。
static class User implements Serializable{ private static final long serialVersionUID = 1L; private String username = null; private transient String password = null; //使用 transient 关键字标明该变量值不会被序列化到字节流中 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
二,特例分析
了解了transient关键字的作用后,下面来看几个特殊的例子。Map和Set等集合类的序列化实现。JDK源码如下(HashMap为例):
/**HashMap序列化实现**/ public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry[] table; //存放数据的table /** * The number of key-value mappings contained in this map. */ transient int size;//数据的个数 }
通过JDK源码发现,HashMap对于存放数据的变量table和大小size,都使用了transient关键字修饰(即不序列化该变量)。那么HashMap又是如何完成对数据序列化的呢?
继续阅读JDK源码,发现HashMap自己实现了一套writeObject,和readObject方法。
/** * Save the state of the <tt>HashMap</tt> instance to a stream (i.e., * serialize it). * * @serialData The <i>capacity</i> of the HashMap (the length of the * bucket array) is emitted (int), followed by the * <i>size</i> (an int, the number of key-value * mappings), followed by the key (Object) and value (Object) * for each key-value mapping. The key-value mappings are * emitted in no particular order. */ private void writeObject(java.io.ObjectOutputStream s) throws IOException { Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null; // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); // Write out number of buckets s.writeInt(table.length); // Write out size (number of Mappings) s.writeInt(size); // Write out keys and values (alternating) if (i != null) { while (i.hasNext()) { Map.Entry<K,V> e = i.next(); s.writeObject(e.getKey()); s.writeObject(e.getValue()); } } } private static final long serialVersionUID = 362498820763181265L; /** * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e., * deserialize it). */ private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the threshold, loadfactor, and any hidden stuff s.defaultReadObject(); // Read in number of buckets and allocate the bucket array; int numBuckets = s.readInt(); table = new Entry[numBuckets]; init(); // Give subclass a chance to do its thing. // Read in size (number of Mappings) int size = s.readInt(); // Read the keys and values, and put the mappings in the HashMap for (int i=0; i<size; i++) { K key = (K) s.readObject(); V value = (V) s.readObject(); putForCreate(key, value); } }
当使用ObjectOutputStream writeObject序列化对象时,如果该对象有writeObject方法则调用该对象的writeObject方法(通过反射实现),这样达到序列化重写的目的。JDK源码如下:
/** * Writes instance data for each serializable class of given object, from * superclass to subclass. * ObjectOutputStream writeObject会调用writeSerialData完成对实现Serializable标志 性接口的序列化 */ private void writeSerialData(Object obj, ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); for (int i = 0; i < slots.length; i++) { ObjectStreamClass slotDesc = slots[i].desc; if (slotDesc.hasWriteObjectMethod()) {//待序列化对象是否包含writeObject方法 PutFieldImpl oldPut = curPut; curPut = null; if (extendedDebugInfo) { debugInfoStack.push( "custom writeObject data (class \"" + slotDesc.getName() + "\")"); } SerialCallbackContext oldContext = curContext; try { curContext = new SerialCallbackContext(obj, slotDesc); bout.setBlockDataMode(true); slotDesc.invokeWriteObject(obj, this);//通过反射调用对象自己的writeObject方法 bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA); } finally { curContext.setUsed(); curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; } else { defaultWriteFields(obj, slotDesc); //待序列化的对象没有writeObject方法,则使用JDK默认的 } } }
三,总结
Map,Set,List等都是使用transient关键字屏蔽变量,然后自己实现的序列化操作。