transient關鍵字的意思

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
         */
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章