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");
}

aVar1aVar3 编译时间常量 ,它们从不通过实例字段读取,但总是直接读取。

所以看起来你确实在做 a1.aVar1,即你访问了一个实例字段 - 但你从来没有这样做过。就像直接做:System.out.println(3)

另一方面,根据JLS.

,其余实例字段不是compile time constants

在反序列化过程中,没有调用对象的构造函数。这是JVM处理的特殊对象实例化过程。

对于 aVar2 和 aVar4,调用了 Hashmap 和字符串构造函数。所以这些变量被赋予了默认值(null)。

对于aVar1 和aVar3,一些常量表达式被分配给它们。这些称为编译时间常数。

编译时常量的条件是

  1. 它们必须被声明为最终的
  2. 它们是原始数据类型或String
  3. 它们必须用它们的声明来初始化。
  4. 它们的值必须是常量表达式。

编译时间常量重新受到影响,这些值将在反序列化后保留。