transient
java語言的關鍵字,變量修飾符,如果用transient聲明一個實例變量,當對象存儲時,它的值不需要維持。換句話來說就是,用transient關鍵字標記的成員變量不參與序列化過程。
作用
Java的serialization提供了一種持久化對象實例的機制。當持久化對象時,可能有一個特殊的對象數據成員,我們不想用serialization機制來保存它。爲了在一個特定對象的一個域上關閉serialization,可以在這個域前加上關鍵字transient。當一個對象被序列化的時候,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進去的。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
/**
* Pointer to first node.
*/
transient Node<E> first;
/**
* Pointer to last node.
*/
transient Node<E> last;
....
}
應用場景:使用IO流的ObjectOutputStream來持久化對象時:
package Stream_IntOut;
import classandobject.Person;
import java.io.*;
/**
* 場景:進行一次網上交易,突然服務器中斷,我們必須時時刻刻將交易的相關類的信息保存。
* 等服務器恢復,我們在重新加載該類,則能恢復之前的交易狀態,維持數據不變。
*
* 也就是說我們需要能夠對類、對象進行保存到硬盤等外設。使得對象持久化。
* ——ObjectOutputStream
*
* public class ObjectOutputStream
* extends OutputStream
* implements ObjectOutput, ObjectStreamConstants
* ObjectOutputStream將Java對象的基本數據類型和對象寫入OutputStream。
* 可以使用ObjectInputStream讀取(重構)對象。
* 可以通過使用流的文件來完成對象的持久存儲。 如果流是網絡套接字流,則可以在另一個主機或另一個進程中重新構建對象。
*
* 只有支持java.io.Serializable接口的對象才能寫入流。 每個可序列化對象的類都被編碼,包括類的類名和簽名,對象的字段和數組的值,
* 以及從初始對象引用的任何其他對象的閉包。 ——serializableVersionID
*
* writeObject方法用於將對象寫入流。 任何對象,包括字符串和數組,都是用writeObject編寫的。
* 可以將多個對象或基元寫入流中。
* !!!必須從相應的ObjectInputStream中讀取對象,這些對象具有與寫入時相同的類型和順序。 (其—serializableVersionID相同纔可以
* 讀取,否則會拋出異常:InvalidClassException
*
* 也可以使用DataOutput中的適當方法將基本數據類型寫入流中。 也可以使用writeUTF方法編寫字符串。
*
* 對象的默認序列化機制會寫入對象的類,類簽名以及所有非瞬態(不用transient標示的)和非靜態字段的值。
* 對其他對象的引用(瞬態或靜態字段除外)也會導致這些對象被寫入。 使用引用共享機制對對單個對象的多個引用進行編碼,
*/
public class Practice12_ObjectOutputStream {
public static void main(String[]args) throws IOException, ClassNotFoundException {
// writeObjectDemo();
// System.out.println("寫入Person對象完畢!");
readObjectDemo();
}
public static void readObjectDemo() throws IOException, ClassNotFoundException {
//ObjectInputStream只能用來讀取由ObjectOutputStream寫入的對象。
// 而且要存儲對象的serialVersionUID與字節碼文件的serialVersionUID相同纔可反序列化。讀取該對象。
ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("E:\\Object.txt"));
Person p = (Person)ooi.readObject();//當對應的serialVersionUID不同,會報錯,無法加載保存到硬盤的對象。
/*
報錯信息
Exception in thread "main" java.io.InvalidClassException: classandobject.Person;
local class incompatible: stream classdesc serialVersionUID = 2564213078493790751,
local class serialVersionUID = -4578207210445382436
所以一般爲了防止當存放了對象,而對類的一些屬性修改了。進而導致的ID不一致
通常使用顯示聲明ID,當然一般不要修改。
*/
System.out.println(p.getName()+" :"+p.getAge());
//接下來演示靜態變量無法寫入對象時存儲到硬盤。
//將age改爲了靜態。
/*
結果:lisi :0,明明我們存放的不該是lisi 22嗎?說明靜態變量根本沒有存進去。
*/
//接下來演示transient關鍵字
//將age改爲 private transient int age;
/*
* 結果lisi :0,明明我們存放的不該是lisi 22嗎?說明非瞬態的變量根本沒有存進去。
* 所以transient就這個作用。
* 而當我們有一些變量,我們不想寫入對象時將其寫入硬盤,但它又不是靜態的時候,
* 我們可以聲明它爲瞬時的——關鍵字transient
*/
ooi.close();
}
public static void writeObjectDemo() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\Object.txt"));//一般以object後綴結尾,表示對象持久化文件。
oos.writeObject(new Person("lisi",22));//當沒有該對象沒有實現Serializable接口,就會無法序列化。
//報錯Exception in thread "main" java.io.NotSerializableException: classandobject.Person
oos.close();
/*
注意寫入內容是:
對象的類,類簽名以及所有非瞬態(不用transient標示的)和非靜態字段的值。
對其他對象的引用(瞬態或靜態字段除外)也會導致這些對象被寫入。
因爲靜態變量處於方法區的靜態方法區,也就是堆中。
而當我們有一些變量,我們不想寫入對象時將其寫入硬盤,但它又不是靜態的時候,
我們可以聲明它爲瞬時的——關鍵字transient
*/
}
}