在 Java 中,静态变量属于类级别,而不是对象级别。当一个类被加载时,它的静态变量就会被初始化,并在 JVM 进程内存中保持不变,直到 JVM 进程结束。因此,对静态变量的修改只对当前 JVM 进程有效,不会影响到序列化和反序列化的操作。
当一个对象被反序列化时,Java 会根据序列化数据流中的信息重建对象,并恢复对象的状态。这时,如果序列化数据流中包含静态变量的信息,Java 会使用该信息对静态变量进行赋值。但是,由于静态变量的值在 JVM 进程中保持不变,因此对静态变量的修改不会影响到反序列化的结果。
需要注意的是,在序列化和反序列化操作中,静态变量是不会被序列化和反序列化的。这意味着,如果一个类的静态变量发生了变化,只有在下一次 JVM 进程启动时才会生效,而不会影响到已经序列化的数据。因此,对于需要在序列化和反序列化中使用的变量,应该声明为实例变量,而不是静态变量。
序列化版本号可自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,这样随着class的升级,就无法正确反序列化;不指定版本号另一个明显隐患是,不利于jvm间的移植,可能class文件没有更改,但不同jvm可能计算的规则不一样,这样也会导致无法反序列化。
什么情况下需要修改serialVersionUID呢?分三种情况。
如果只是修改了方法,反序列化不容影响,则无需修改版本号;
如果只是修改了静态变量,瞬态变量(transient修饰的变量),反序列化不受影响,无需修改版本号;
如果修改了非瞬态变量,则可能导致反序列化失败。如果新类中实例变量的类型与序列化时类的类型不一致,则会反序列化失败,这时候需要更改serialVersionUID。如果只是新增了实例变量,则反序列化回来新增的是默认值;如果减少了实例变量,反序列化时会忽略掉减少的实例变量。