抽象类是否应该具有串行版本 UID
在java中,如果一个类实现了Serializable但是是抽象的,那么它应该有一个串行VersionUID long声明,还是子类只要求这样做?
在这种情况下,确实是所有子类都处理序列化的意图,因为该类型的目的是在RMI调用中使用。
在java中,如果一个类实现了Serializable但是是抽象的,那么它应该有一个串行VersionUID long声明,还是子类只要求这样做?
在这种情况下,确实是所有子类都处理序列化的意图,因为该类型的目的是在RMI调用中使用。
提供 serialVersionUID 是为了确保反序列化对象与该类的当前版本之间的兼容性。因此,在类的第一个版本中,或者在本例中,在抽象基类中,实际上并不需要这样做。您永远不会有该抽象类的实例来序列化/反序列化,因此它不需要 serialVersionUID。
(当然,它确实会生成一个编译器警告,你想摆脱它,对吧?
事实证明,詹姆斯的评论是正确的。抽象基类的串行VersionUID确实会传播到子类。有鉴于此,您确实需要在基类中使用 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,使其创建并保存对象。然后更改基类中的 serialVersionUID,注释掉 main 中保存对象的行(因此它不会再次保存它,你只想加载旧的),然后再次运行它。这将导致异常
java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
是的,一般来说,出于与任何其他类需要串行ID相同的原因 - 以避免为其生成一个串行ID。基本上,任何实现可序列化的类(不是接口)都应该定义串行版本 ID,否则当服务器和客户端 JVM 中不存在相同的.class编译时,您就有可能出现反序列化错误。
如果您尝试做一些花哨的事情,还有其他选择。我不确定你说的“这是子类的意图......”是什么意思。是否要编写自定义序列化方法(例如,writeObject、readObject)?如果是这样,还有其他选项来处理超类。
请参见: http://java.sun.com/javase/6/docs/api/java/io/Serializable.html
汤姆