有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我已经读到,一般来说,抽象类不应该在Java中序列化。子类应该是可序列化的(如果需要,可以使用定制的读写方法,例如当抽象类有字段时)

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

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

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

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

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

在自定义的读写方法中,我调用这些子类中的方法来(反)序列化抽象类中的字段。这种方法正确吗?还是有其他更好的方法

更新2:我采纳了Tom的建议,使我的抽象类可序列化。(我希望所有的子类都是可序列化的,并且抽象类中有数据)这是一个旁白,但为了完成我正在使用的reflection to change final fields as advised by Jeremy Manson.


共 (5) 个答案

  1. # 1 楼答案

    我不知道这一定是糟糕的设计。序列化实际上是一个实现问题(注意,Josh Bloch不同意我的观点),因此对于接口来说没有意义。如果抽象类具有state,则希望使其可序列化。如果它没有状态,就没有理由这样做

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

    注意java.io.Serializable是一种黑客行为。它不应该是一个接口。注释(或者像transient这样的语言演变)更合适

    和往常一样,最好选择组合而不是继承,不要使随机类可序列化

  2. # 2 楼答案

    让我们看一看oposite的位置。如果要反序列化对象,其类型是什么

    根据定义,抽象类不能被实例化。如果您可以序列化它,这意味着它也可以被反序列化,这将为您提供一个抽象类的实例。这与抽象类的定义相矛盾,因此无法实现

  3. # 3 楼答案

    我认为原因是,如果抽象类实现了可序列化,那么就没有办法说子类型不应该是可序列化的。最好让每个具体类型自己声明

  4. # 4 楼答案

    如果abstract类包含重要的for序列化字段,并且您不打算实现自定义对象读写器,那么将该基类声明为Serializable是必要的

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

    如果您实现了某种框架,后者是有意义的:您可以让用户轻松地自动传播接口,否则您应该记录您仅使用Serializable或对用户提供的类执行运行时检查

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

    更新Serializable需要公共无参数构造函数进行反序列化。继承声明不会为子类或超类创建任何参数构造函数,这是用户的杂务。没有默认构造函数的超类会中断所有子类的反序列化)

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

    private void writeObject(ObjectOutputStream out) throws IOException
    { throw new NotSerializableException(); }
      
    private void readObject(ObjectInputStream in) throws IOException
    { throw new NotSerializableException(); }
    
  5. # 5 楼答案

    这只是一个糟糕的设计,因为这是一个强制的决定,如果您想要一个具有不可序列化成员的子类,该怎么办

    这就是为什么

    例如,列表是不可序列化的,但每个主要的列表实现都是可序列化的。(我知道list是一个接口,但它是一个没有成员的抽象类=/=接口)