首先我需要解释一下什么是序列化。
序列化允许将对象转换为流,以便通过网络发送该对象或保存到文件或保存到数据库以供字母使用。
序列化有一些规则。
-
一个对象只有在其类或其超类实现了 Serializable 接口时才可序列化
-
一个对象是可序列化的(它自己实现了 Serializable 接口),即使它的超类不是。然而,可序列化类的层次结构中的第一个超类,没有实现可序列化接口,必须有一个无参数的构造函数。如果违反了,readObject() 将在运行时产生 java.io.InvalidClassException
-
所有原始类型都是可序列化的。
-
瞬态字段(带有瞬态修饰符)未序列化(即未保存或恢复)。实现 Serializable 的类必须标记不支持序列化的类的瞬态字段(例如,文件流)。
-
静态字段(带有静态修饰符)未序列化。
当Object 被序列化时,Java 运行时会关联序列版本号,也就是serialVersionID。
我们需要serialVersionID的地方:
在反序列化期间验证发送方和接收方在序列化方面是否兼容。如果接收方使用不同的serialVersionID 加载类,则反序列化将以InvalidClassCastException 结束。
可序列化类可以通过声明一个名为 serialVersionUID 的字段来显式声明自己的 serialVersionUID,该字段必须是静态的、最终的和 long 类型。
让我们用一个例子来试试这个。
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;
public String getEmpName() {
return name;
}
public void setEmpName(String empname) {
this.empname = empname;
}
public byte getEmpAge() {
return empage;
}
public void setEmpAge(byte empage) {
this.empage = empage;
}
public String whoIsThis() {
return getEmpName() + " is " + getEmpAge() + "years old";
}
}
创建序列化对象
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
Employee employee = new Employee();
employee.setEmpName("Jagdish");
employee.setEmpAge((byte) 30);
FileOutputStream fout = new
FileOutputStream("/users/Jagdish.vala/employee.obj");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(employee);
oos.close();
System.out.println("Process complete");
}
}
反序列化对象
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Employee employee = new Employee();
FileInputStream fin = new FileInputStream("/users/Jagdish.vala/employee.obj");
ObjectInputStream ois = new ObjectInputStream(fin);
employee = (Employee) ois.readObject();
ois.close();
System.out.println(employee.whoIsThis());
}
}
注意:现在更改 Employee 类的 serialVersionUID 并保存:
private static final long serialVersionUID = 4L;
并执行 Reader 类。不执行 Writer 类会报异常。
Exception in thread "main" java.io.InvalidClassException:
com.jagdish.vala.java.serialVersion.Employee; local class incompatible:
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)