Yis*_*hai 62 java serialization abstract-class serialversionuid
在java中,如果一个类实现Serializable但是是抽象的,它是否应该声明一个longVersionUID,或者子类只需要它?
在这种情况下,确实意图是所有子类都处理序列化,因为该类型的目的是在RMI调用中使用.
Bil*_*ard 46
提供serialVersionUID是为了确定deseralized对象与类的当前版本之间的兼容性. 因此,在类的第一个版本中,或者在这种情况下,在抽象基类中并不是必需的.您将永远不会有该抽象类的实例来序列化/反序列化,因此它不需要serialVersionUID.
(当然,它会生成一个编译器警告,你想摆脱它,对吧?)
事实证明詹姆斯的评论是正确的.抽象基类的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() );
}
}
Run Code Online (Sandbox Code Playgroud)
在Sub中运行main以使其创建并保存对象.然后更改Base类中的serialVersionUID,注释掉main中保存对象的行(因此它不再保存它,你只想加载旧的),然后再次运行它.这将导致异常
java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
Run Code Online (Sandbox Code Playgroud)
是的,通常,出于同样的原因,任何其他类都需要一个序列ID - 以避免为它生成一个.基本上,任何实现serializable的类(不是接口)都应该定义串行版本ID,否则当同一个.class编译不在服务器和客户端JVM中时,就会出现反序列化错误.
如果你想做一些奇特的事,还有其他选择.我不确定你的意思是"这是子类的目的......".你打算编写自定义序列化方法(例如writeObject,readObject)吗?如果是这样,还有其他选择来处理超类.
请参阅: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)
Run Code Online (Sandbox Code Playgroud)
因此,当您反序列化时,层次结构中任何类的版本不匹配都会导致反序列化失败。没有为接口存储任何内容,因此无需为它们指定版本。
所以答案是:是的,你确实需要serialVersionUID在抽象基类中提供,即使它没有字段:className+version仍然被存储。
另请注意以下事项:
Object的字段String,则将字段类型更改为String将会成功,但将其更改为 则Integer不会成功。但是,即使您可以为变量赋值,将字段从更改为int也long不起作用。intlong简而言之:您可以重新排序字段、添加和删除它们,甚至更改类层次结构。您不应该重命名字段或类(它不会失败,但会像删除并添加该字段一样进行处理)。您无法更改原始类型的字段类型,并且可以更改引用类型字段,前提是新类型可从所有序列化值分配。
注意:如果基类未实现Serializable而只有子类实现,则基类中的字段将表现为transient.
| 归档时间: |
|
| 查看次数: |
17346 次 |
| 最近记录: |