簡體   English   中英

序列化Java中的最終瞬態如何工作

[英]How transient works with final in Serialization Java

我正在閱讀有關transient和final關鍵字的內容,我找到了一個答案,我們不能使用帶有final關鍵字的transient關鍵字。 我試過並感到困惑,因為這里工作正常。

import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class SerExample{
    public static void main(String... args){
        Student foo = new Student(3,2,"ABC");
        Student koo = new Student(6,4,"DEF");
        try
        {
            FileOutputStream fos = new FileOutputStream("abc.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(foo);
            oos.writeObject(koo);
            oos.close();
            fos.close();
        }
        catch(Exception e){/**/}

        try{
            FileInputStream fis = new FileInputStream("abc.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
            System.out.println(ois.readObject());
            System.out.println(ois.readObject());
            fis.close();
            ois.close();
        }catch(Exception e){/**/}
    }
}

這是Serializable Student類代碼:

class Student implements Serializable{
        private transient final int id;
        private transient static int marks;
        private String name;
        public Student(int id, int marks, String name){
            this.id = id;
            this.marks = marks;
            this.name = name;
        }
        public Student(){
            id=0;
        }
        @Override
        public String toString(){
            return (this.name + this.id + this.marks);
        }
    }

帶有transient關鍵字的代碼輸出。

ABC04
DEF04

輸出沒有臨時關鍵字。

ABC34
DEF64

你能解釋為什么它工作正常嗎? 有沒有錯誤?

最后什么應該是具有final關鍵字的瞬態行為?

你的問題有點與此重復:

必須通過直接賦值初始值或在構造函數中初始化final字段。 在反序列化期間,這些都不會被調用,因此必須在反序列化期間調用的“readObject()”私有方法中設置瞬態的初始值。 為了實現這一目標,瞬態必須是非最終的。

聲明為transient的任何字段都不是序列化的。 此外,根據此博客文章,字段值甚至不會初始化為默認構造函數設置的值。 當瞬態場是最終的時,這會產生挑戰。

至於你的測試結果:

帶有transient關鍵字的代碼輸出。 ABC04 DEF04
輸出沒有臨時關鍵字。 ABC34 DEF64

短暫的

顯然, transient字段(第4個字符)未被序列化/反序列化(ABC 3 4-> ABC 0 4和DEF 6 4-> DEF 0 4)

靜態的

static字段(第5個字符)也沒有被反序列化! 這只是因為您在同一個內存空間中執行操作,靜態字段保留在所有實例中。 因此,當您在學生上設置靜態字段,然后反序列化另一個學生時,靜態字段當然仍然具有相同的值!

這也解釋了為什么在測試中你首先將靜態字段設置為2然后是4 ,但只打印4 在這種情況下,與序列化無關,只是靜態字段行為。

你的例子有效的結論是錯誤的。

  1. 字段name不是transient ,因此可以正確存儲,恢復和打印。
  2. 字段marks聲明為static ,因此不是對象狀態的一部分,永遠不會存儲也不會恢復。 它始終顯示最后寫入的值4 ,盡管您的第一個對象已寫入2 ,因為第二個對象在測試開始之前用4覆蓋它。
  3. 只有字段id是未存儲的transient實例字段,因此顯示默認值0 刪除transient關鍵字時,它會被存儲和恢復,第一個顯示3 ,第二個顯示6

也許它可以幫助你,如果你添加間距甚至標識符,如
"name="+name+", id="+id+""+", marks="+marks字符串表示中的"name="+name+", id="+id+""+", marks="+marks
toString()返回。

如果添加字段,則添加另一個案例,產生反直覺行為

transient final int foo = 42;

對於您的類,您還將體驗它以在還原后顯示正確的值,因為它是編譯時常量。 因此,引用此變量的任何代碼都將始終使用常量值,並且永遠不會實際讀取實例字段,因此未恢復的事實不會被忽視。 但是,當然,這樣的常量更好地聲明為static以避免浪費內存用於永不讀取的實例字段。

另一個可能令人驚訝的例子是在enum聲明transient final字段。 它們總是顯示正確的值,因為enum對象的狀態永遠不會存儲,但是在反序列化enum值時,將解析該enum類型的實際已經初始化的常量對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM