transient如何在Java中与final序列化一起工作
我读了一些关于transient和final关键字的文章,我发现答案是我们不能将transient关键字与final关键字一起使用。我试过了,但弄糊涂了,因为它在这里工作得很好transient如何在Java中与final序列化一起工作,java,serialization,java-8,final,transient,Java,Serialization,Java 8,Final,Transient,我读了一些关于transient和final关键字的文章,我发现答案是我们不能将transient关键字与final关键字一起使用。我试过了,但弄糊涂了,因为它在这里工作得很好 import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.Serializable
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){/**/}
}
}
以下是可序列化的学生班级代码:
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
不带瞬态关键字的输出
ABC04
DEF04
ABC34
DEF64
你能解释一下为什么它工作得很好吗?有虫子吗
最后,带final关键字的transient的行为应该是什么?您的问题有点重复:
不带瞬态关键字的输出。 ABC34 DEF64 转瞬即逝的 显然,
transient
字段(第4个字符)没有被序列化/反序列化(ABC34->ABC04和DEF64->DEF04)
静止的
静态
字段(第5个字符)也没有被反序列化!这仅仅是因为您在相同的内存空间中执行操作,并且静态字段保留在所有实例中。因此,当您在student上设置静态字段,然后反序列化另一个student时,静态字段当然仍然具有相同的值
这也解释了为什么在测试中首先将静态字段设置为2
,然后
然后
4
,但只打印4
。在这种情况下,与序列化无关,只是静态字段行为。您认为示例有效的结论是错误的
name
不是transient
,因此正确存储、还原和打印标记
被声明为静态
,因此不属于对象状态的一部分,也不会存储或恢复。它始终显示最后写入的值,4
,尽管第一个对象已向其写入2
,因为第二个对象甚至在测试开始之前就用4
覆盖它id
是未存储的transient
实例字段,因此显示默认值0
。删除transient
关键字时,将存储并还原该关键字,第一个对象显示3
,第二个对象显示6
“name=“+name+”,id=“+id+”+,marks=“+marks
在字符串表示法中由
toString()
返回
添加另一个角盒,如果添加字段,则会产生违反直觉的行为
transient final int foo = 42;
对于您的类,您还将体验到它在恢复后显示正确的值,因为它是一个编译时常量。因此,任何引用此变量的代码都将始终使用常量值,并且从未实际读取实例字段,因此不会注意到它未被还原的事实。但是,当然,最好声明这样一个常量static
,以避免为从不读取的实例字段浪费内存
另一个可能令人惊讶的例子是在enum
中声明transient final
字段。它们将始终显示正确的值,因为从未存储enum
对象的状态,但在反序列化enum
值时,将解析该enum
类型的实际、已初始化的常量对象