面试题答案
一键面试字段变化在反序列化时可能遇到的问题
- 字段添加:
反序列化时,新添加的字段在旧的序列化数据中不存在,其值会被赋予该字段类型的默认值。例如,若原类
class OldClass implements Serializable { int id; }
,新类class NewClass extends OldClass { int id; String name; }
,反序列化旧数据到新类时,name
字段为null
。 - 字段删除:
若删除的字段在旧序列化数据中有值,反序列化时会丢失该字段的值。例如原类
class OldClass implements Serializable { int id; String name; }
,新类class NewClass implements Serializable { int id; }
,反序列化旧数据到新类时,name
字段的值会被丢弃。 - 字段修改:
包括字段类型修改和字段名称修改。若字段类型修改,反序列化通常会失败并抛出
InvalidClassException
。例如原类class OldClass implements Serializable { int id; }
,新类class NewClass implements Serializable { long id; }
,反序列化会失败。若字段名称修改,类似于字段删除,旧数据中该字段的值会丢失。
通过serialVersionUID进行版本控制
- serialVersionUID的作用:
serialVersionUID
是一个类的版本标识,在序列化和反序列化过程中,JVM会比较类的serialVersionUID
与序列化数据中的serialVersionUID
。如果两者相同,反序列化通常可以顺利进行;如果不同,会抛出InvalidClassException
。 - 设置serialVersionUID:
可以在类中显式定义
serialVersionUID
,例如:
import java.io.Serializable;
public class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
int data;
// 其他方法
}
- 举例说明: 假设初始类如下:
import java.io.Serializable;
public class Version1 implements Serializable {
private static final long serialVersionUID = 1L;
int id;
}
对其进行序列化:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeVersion1 {
public static void main(String[] args) {
Version1 obj = new Version1();
obj.id = 10;
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("version1.ser"))) {
oos.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后类发生了变化,添加了一个字段,同时保持serialVersionUID
不变:
import java.io.Serializable;
public class Version2 implements Serializable {
private static final long serialVersionUID = 1L;
int id;
String name;
}
反序列化代码如下:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializeVersion2 {
public static void main(String[] args) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("version1.ser"))) {
Version2 obj = (Version2) ois.readObject();
System.out.println("Id: " + obj.id);
System.out.println("Name: " + obj.name); // name为null
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在这个例子中,由于serialVersionUID
未改变,虽然数据是由Version1
序列化产生,Version2
仍能成功反序列化,只是新添加的name
字段为默认值null
。若改变serialVersionUID
,则反序列化会抛出InvalidClassException
。