Serialization/Deserialization 个最终瞬态场
Serialization/Deserialization of the final transient fields
在 this 问题中说 final
transient
字段在序列化后不能设置为任何非默认值。那么为什么我有 3 个 aVar1
变量和 s3 个 aVar3
变量?
import java.io.*;
import java.util.*;
class Test
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
A a1 = new A();
// save a1 to file
FileOutputStream fileOutput = new FileOutputStream("a.dat");
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutput);
outputStream.writeObject(a1);
fileOutput.close();
outputStream.close();
// load a1 from file
FileInputStream fiStream = new FileInputStream("a.dat");
ObjectInputStream objectStream = new ObjectInputStream(fiStream);
a1 = (A) objectStream.readObject();
fiStream.close();
objectStream.close();
// fields after deserialization
System.out.println(a1.aVar1); // 3
System.out.println(a1.aVar2); // null
System.out.println(a1.aVar3); // s3
System.out.println(a1.aVar4); // null
}
}
class A implements Serializable
{
public final transient int aVar1 = 3;
public final transient Map <Object, Object> aVar2 = new HashMap <> ();
public final transient String aVar3 = "s3";
public final transient String aVar4 = new String("s4");
}
aVar1
和 aVar3
是 编译时间常量 ,它们从不通过实例字段读取,但总是直接读取。
所以看起来你确实在做 a1.aVar1
,即你访问了一个实例字段 - 但你从来没有这样做过。就像直接做:System.out.println(3)
。
另一方面,根据JLS
.
,其余实例字段不是compile time constants
在反序列化过程中,没有调用对象的构造函数。这是JVM处理的特殊对象实例化过程。
对于 aVar2 和 aVar4,调用了 Hashmap 和字符串构造函数。所以这些变量被赋予了默认值(null)。
对于aVar1 和aVar3,一些常量表达式被分配给它们。这些称为编译时间常数。
编译时常量的条件是
- 它们必须被声明为最终的
- 它们是原始数据类型或String
- 它们必须用它们的声明来初始化。
- 它们的值必须是常量表达式。
编译时间常量重新受到影响,这些值将在反序列化后保留。
在 this 问题中说 final
transient
字段在序列化后不能设置为任何非默认值。那么为什么我有 3 个 aVar1
变量和 s3 个 aVar3
变量?
import java.io.*;
import java.util.*;
class Test
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
A a1 = new A();
// save a1 to file
FileOutputStream fileOutput = new FileOutputStream("a.dat");
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutput);
outputStream.writeObject(a1);
fileOutput.close();
outputStream.close();
// load a1 from file
FileInputStream fiStream = new FileInputStream("a.dat");
ObjectInputStream objectStream = new ObjectInputStream(fiStream);
a1 = (A) objectStream.readObject();
fiStream.close();
objectStream.close();
// fields after deserialization
System.out.println(a1.aVar1); // 3
System.out.println(a1.aVar2); // null
System.out.println(a1.aVar3); // s3
System.out.println(a1.aVar4); // null
}
}
class A implements Serializable
{
public final transient int aVar1 = 3;
public final transient Map <Object, Object> aVar2 = new HashMap <> ();
public final transient String aVar3 = "s3";
public final transient String aVar4 = new String("s4");
}
aVar1
和 aVar3
是 编译时间常量 ,它们从不通过实例字段读取,但总是直接读取。
所以看起来你确实在做 a1.aVar1
,即你访问了一个实例字段 - 但你从来没有这样做过。就像直接做:System.out.println(3)
。
另一方面,根据JLS
.
compile time constants
在反序列化过程中,没有调用对象的构造函数。这是JVM处理的特殊对象实例化过程。
对于 aVar2 和 aVar4,调用了 Hashmap 和字符串构造函数。所以这些变量被赋予了默认值(null)。
对于aVar1 和aVar3,一些常量表达式被分配给它们。这些称为编译时间常数。
编译时常量的条件是
- 它们必须被声明为最终的
- 它们是原始数据类型或String
- 它们必须用它们的声明来初始化。
- 它们的值必须是常量表达式。
编译时间常量重新受到影响,这些值将在反序列化后保留。