說明
用transient聲明一個(gè)實(shí)例變量映凳,當(dāng)對(duì)象存儲(chǔ)時(shí)录别,它的值不需要維持耕渴。
作用
Java的serialization提供了一種持久化對(duì)象實(shí)例的機(jī)制拘悦。當(dāng)持久化對(duì)象時(shí),可能有一個(gè)特殊的對(duì)象數(shù)據(jù)成員萨螺,我們不想用serialization機(jī)制來保存它窄做。為了在一個(gè)特定對(duì)象的一個(gè)域上關(guān)閉serialization,可以在這個(gè)域前加上關(guān)鍵字transient慰技。當(dāng)一個(gè)對(duì)象被序列化的時(shí)候椭盏,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進(jìn)去的吻商。
驗(yàn)證
package com.qjk;
import java.io.*;
public class TestTransient {
static class User implements Serializable {
String name;
int age;
transient int transient_age;
String sex;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
User user = new User();
user.age = 12;
user.transient_age = 12;
user.name = "小丸子";
user.sex = "nv";
System.out.println("age:" + user.age);
System.out.println("transient_age:" + user.transient_age);
System.out.println("name:" + user.name);
System.out.println("sex:" + user.sex);
System.out.println("----------------序列化+反序列化----------------");
// 序列化后寫入緩存
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(user);
oos.flush();
oos.close();
byte[] buf = baos.toByteArray();
// 從緩存中讀取并執(zhí)行反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bais);
User u = (User) ois.readObject();
System.out.println("age:" + u.age);
System.out.println("transient_age:" + u.transient_age);
System.out.println("name:" + u.name);
System.out.println("sex:" + u.sex);
}
}
結(jié)果輸出
age:12
transient_age:12
name:小丸子
sex:nv
----------------序列化+反序列化----------------
age:12
transient_age:0
name:小丸子
sex:nv
擴(kuò)展
Exteranlizable
Java序列化提供兩種方式掏颊。一種是實(shí)現(xiàn)Serializable接口。另一種是實(shí)現(xiàn)Exteranlizable接口艾帐。Externalizable接口是繼承于Serializable 乌叶,需要重寫writeExternal和readExternal方法,它的效率比Serializable高一些柒爸,并且可以決定哪些屬性需要序列化(即使是transient修飾的)准浴,但是對(duì)大量對(duì)象,或者重復(fù)對(duì)象捎稚,則效率低乐横。
ArrayList中的transient
下面是ArrayList中的一段代碼
/**
* ArrayList 的元素存儲(chǔ)在其中的數(shù)組緩沖區(qū)。 ArrayList 的容量就是這個(gè)數(shù)組緩沖
* 區(qū)的長度今野。添加第一個(gè)元素時(shí)葡公,任何帶有 elementData ==
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都將擴(kuò)展為
* DEFAULT_CAPACITY。
*/
transient Object[] elementData; // non-private to simplify nested class access
ArrayList提供了自定義的wirteObject和readObject方法:
/**
* 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[i]);
}
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
int capacity = calculateCapacity(elementData, size);
SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
我理解這里定義elementData為transient是為了防止數(shù)據(jù)重復(fù)被寫入磁盤条霜,節(jié)省空間催什。
如果對(duì)象聲明了readObject和writeObject方法,對(duì)象在被序列化的時(shí)候會(huì)執(zhí)行對(duì)象的readObject和writeObject方法宰睡。
靜態(tài)屬性
靜態(tài)屬性蒲凶,無論是否被transient修飾气筋,都不會(huì)被序列化。