在这种情况下,的确打算让所有子类处理序列化,因为该类型的目的是用于RMI调用。
serialVersionUID用于确定反序列化对象与当前类的版本之间的兼容性。在一个类的第一个版本或者在这种情况下,抽象基类中实际上并不是必需的。因为您永远不会拥有该抽象类的实例来进行序列化/反序列化,所以它不需要serialVersionUID。
(当然,它会生成一个编译器警告,你想要消除它,对吧?)
事实证明,james的评论是正确的。抽象基类的serialVersionUID确实会传播到子类。因此,在您的基类中需要serialVersionUID。
测试代码:
import java.io.Serializable;
public abstract class Base implements Serializable {
private int x = 0;
private int y = 0;
private static final long serialVersionUID = 1L;
public String toString()
{
return "Base X: " + x + ", Base Y: " + y;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Sub extends Base {
private int z = 0;
private static final long serialVersionUID = 1000L;
public String toString()
{
return super.toString() + ", Sub Z: " + z;
}
public static void main(String[] args)
{
Sub s1 = new Sub();
System.out.println( s1.toString() );
// Serialize the object and save it to a file
try {
FileOutputStream fout = new FileOutputStream("object.dat");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject( s1 );
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
Sub s2 = null;
// Load the file and deserialize the object
try {
FileInputStream fin = new FileInputStream("object.dat");
ObjectInputStream ois = new ObjectInputStream(fin);
s2 = (Sub) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println( s2.toString() );
}
}
运行 Sub 类中的 main 方法一次,以便它创建并保存一个对象。然后更改 Base 类中的 serialVersionUID,在 main 中注释掉保存对象的行(这样它就不会再次保存,你只是想加载旧的对象),然后再次运行。这将导致一个异常。
java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
通常情况下,与其他类一样,任何其他类都需要一个序列化标识符 - 以避免为其生成标识符。基本上,任何实现可序列化的类(不是接口)都应该定义序列化版本 id,否则当相同的 .class 编译器不在服务器和客户端 JVM 中时,会出现反序列化错误。
如果您正在尝试做一些花哨的事情,还有其他选项。我不确定您所说的“子类的意图是什么”。您是否将编写自定义序列化方法(例如,writeObject、readObject)?如果是这样,处理超类的其他选项。
see: http://java.sun.com/javase/6/docs/api/java/io/Serializable.html
HTH Tom
在概念上,序列化的数据看起来像这样:
subClassData(className + version + fieldNames + fieldValues)
parentClassData(className + version + fieldNames + fieldValues)
... (up to the first parent, that implements Serializable)
实际上,如果Tom的链接缺少serialVersionID
,则实际上是由序列化运行时计算的,即在编译期间不进行计算。
如果可序列化类没有显式声明
serialVersionUID
,则序列化运行时将根据类的各个方面计算该类的默认serialVersionUID
值...
这使得事情变得更加复杂,因为JRE有不同的版本。