为什么不在Java中序列化抽象类?

时间:2010-12-15 17:26:00

标签: java oop serialization abstract-class

我已经读过,通常抽象类不应该在Java中使用Serializable。子类应该是可序列化的(如果需要,可以使用自定义读取,写入方法,例如,当抽象类具有字段时)。

这背后的原因是什么?为什么它被认为是糟糕的设计?

Update1:​​我有一个抽象类,包含一些字段和三个子类。截至目前,我正在使用以下方法。

我已经使用自定义读取,写入方法使所有子类可序列化。在抽象类中,我有以下方法。

void writeFields(ObjectOutputStream out)throws IOException { .... }

void readFields(ObjectInputStream in) throws IOException, ClassNotFoundException{ ... }

在自定义读取,子类中的write方法中,我调用这些方法来(de)序列化抽象类中的字段。这种方法是否正确?或者有更好的方法吗?

更新2:我接受了Tom的建议并制作了我的抽象类Serializable。 (我希望所有子类都是Serializable,我在抽象类中有数据)这是一个旁边,但只是为了完成我正在使用的故事reflection to change final fields as advised by Jeremy Manson.

5 个答案:

答案 0 :(得分:7)

我认为原因是如果Abstract类实现Serializable,则无法说子类型不应该是Serializable。最好让每个具体类型为自己声明......

答案 1 :(得分:3)

让我们采取相反的立场。如果您要对对象进行反序列化,那么它的类型是什么?

根据定义,无法实例化抽象类。如果你可以序列化它,这意味着它也可以被反序列化,并且会得到一个抽象类的实例。这与抽象类的定义相矛盾,因此无法完成。

答案 2 :(得分:3)

我不知道这一定是糟糕的设计。序列化实际上是一个实现问题(注意,Josh Bloch不同意我的观点),因此对接口没有意义。如果抽象类具有状态,那么您可能希望将其设置为可序列化。如果它没有状态,那么实际上没有任何理由这样做。

我们举一个例子。 java.security.cert.Certificate是一个抽象的可序列化类,具有"type"可序列化字段。如果它不可序列化,则子类不可能是可序列化的并且设置该字段。你会被迫进入黑客行列。

请注意java.io.Serializable是一个黑客攻击。它不应该是一个接口。注释(或类似transient的语言演变)会更合适。

与往常一样,最好选择合成继承而不是随机类可序列化。

答案 3 :(得分:0)

它只是糟糕的设计,因为它是一个强制决定,如果你想要一个具有非可序列化成员的子类,那该怎么办呢。

这就是原因。

E.g。 List不是Serializable,但每个主要列表实现都是。 (我知道list是一个接口,但是没有成员的抽象类= / =接口)

答案 4 :(得分:0)

如果 abstract 类包含重要的序列化字段,并且您不打算实现自定义对象读取器/写入器,则必须将该基类声明为 Serializable。< /p>

将基类(或接口)声明为 Serializable 会使所有子类 Serializable 包括任何传递路径。

如果你实现了一些框架,后者是有意义的:你可以让你的用户自动传播接口,否则你应该记录你只使用 Serializable 或为用户提供的类实现运行时检查。

我为实体添加了基类(为了统一命名标准,对于 idcreatedDateupdatedDate 等字段),但忘记将其标记为 Serializable。因此,任何保存在会话存储 (Redis) 中的实体在反序列化时都具有 null id 值 )) 您不希望这样。

UPDATE Serializable 需要公共无参数构造函数进行反序列化。继承声明不会为子类或超类创建无参数构造函数,这是用户的苦差事。没有默认构造函数的超类会破坏所有子类的反序列化 ))

UPDATE 2 有一种方法可以声明子类不是为序列化而设计的,即使它是从 Serialazable 基类继承的,尽管它是运行时特性:

private void writeObject(ObjectOutputStream out) throws IOException
{ throw new NotSerializableException(); }
  
private void readObject(ObjectInputStream in) throws IOException
{ throw new NotSerializableException(); }