[英]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
。 在這種情況下,與序列化無關,只是靜態字段行為。
你的例子有效的結論是錯誤的。
name
不是transient
,因此可以正確存儲,恢復和打印。 marks
聲明為static
,因此不是對象狀態的一部分,永遠不會存儲也不會恢復。 它始終顯示最后寫入的值4
,盡管您的第一個對象已寫入2
,因為第二個對象在測試開始之前用4
覆蓋它。 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.