终于搞懂序列化中的静态变量和瞬间变量了

341 阅读2分钟

本文主要讲述了在序列化和反序列化过程中,静态变量和类变量的序列化规则,并附带了实验佐证。

先放结论: Java的静态变量不会被序列化:静态变量属于类本身,而不是类的某个特定实例。即使在序列化之前修改了静态变量的值,序列化后得到的新对象的静态变量也将是类变量的初始值。
成员变量被transient标记,那它就是瞬间变量。JVM 在序列化过程中跳过瞬态变量,这意味着在序列化对象时不会存储age变量的值。反序列化对象时,瞬间变量也不会被恢复为定义类时的初始值,而是会初始化为Java类型的默认值。例如,对于int类型,这个默认值是0。

下面进行验证:

给定Student类,实现了序列化接口。成员变量age被定义为瞬间变量,初始值是11;staticCount是静态变量,初始值是1;studentId和name为普通的成员变量。

public class Student implements Serializable {
    private long studentId;
    private String name;
    private transient  int age = 11;
    private static int staticCount = 1;

    public Student(long studentId, String name, int age) {
        super();
        this.studentId = studentId;
        this.name = name;
        this.age = age;

        System.out.println("Constructor");
    }

    @Override
    public String toString() {
        return String.format("%d - %s - %d - %d", studentId, name, age,staticCount);
    }

    public long getStudentId() {
        return studentId;
    }

    public void setStudentId(long studentId) {
        this.studentId = studentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static int getStaticCount() {
        return staticCount;
    }

    public static void setStaticCount(int staticCount) {
        Student.staticCount = staticCount;
    }
}

声明一个student实例,初始化studentId、name、age,修改类变量的值,然后再进行序列化

public class BeforeSerialized {
    public static void main(String[] args) {
        String filePath = "students.ser";
        Student student = new Student(123, "John", 22);
        Student.setStaticCount(2);
        try (
                FileOutputStream fos = new FileOutputStream(filePath);
                ObjectOutputStream outputStream = new ObjectOutputStream(fos);
        ) {

            outputStream.writeObject(student);

        } catch (IOException ex) {
            System.err.println(ex);
        }

    }
}

反序列化得到一个新实例student。

public class AfterSerialized {
    public static void main(String[] args) {
        String filePath = "students.ser";
        try (
                FileInputStream fis = new FileInputStream(filePath);
                ObjectInputStream inputStream = new ObjectInputStream(fis);
        ) {

           Student student = (Student) inputStream.readObject();

            System.out.println(student);

        } catch (ClassNotFoundException ex) {
            System.err.println("Class not found: " + ex);
        } catch (IOException ex) {
            System.err.println("IO error: " + ex);
        }
    }
}

打印结果如下。
studentId=123,name=John:保留了序列化前的对象的值,证明普通成员变量是可被序列化的;

age=0:没有保留序列化前的对象的age=22,也不是类定义中的age=11,而是age属于的int类型的默认值,证明瞬间变量在序列化过程中被跳过并且依据Java类型的默认值进行初始化。

staticCount=1:没有保留序列化前修改的staticCount=2,而是类定义中的staticCount=1,证明静态变量仍是静态变量的初始值。