ObjectInputStream - 读取对象 - 有没有办法阻止调用无参数超类构造函数?

Posted

技术标签:

【中文标题】ObjectInputStream - 读取对象 - 有没有办法阻止调用无参数超类构造函数?【英文标题】:ObjectInputStream - reading an object - Is there a way to prevent a call to a no arg superclass constructor? 【发布时间】:2019-06-16 13:05:39 【问题描述】:

我正在使用 Fileiostreams 和 ObjectIOStreams 将 PreferedCustomer 对象写入 .dat 文件。 我正在练习继承,所以有一个简单的类层次结构。

PreferredCustomer.java 继承自 Customer.java

Customer.java 继承自 Person.java。

当我从 .dat 文件中读取我的 PreferredCustomer 对象时,它调用 Person.java 无参数构造函数并将 Name、Address 和 PhoneNumber 字段设置为“”。如何防止它调用重置字符串值的无参数构造?

我将项目托管在 github 上。 https://github.com/davidmistretta/CustomerObjectDAT

我认为需要修改的代码在 Consumers -> src -> CustomerDemo -> StoreConsumerObjects.java 第 30->40 行(下面的 try/catch 语句)

写入对象然后读取对象的主方法

public static void main(String[] args)

    try (FileOutputStream fos = new FileOutputStream("customers.dat");
         ObjectOutputStream oos = new ObjectOutputStream(fos)) 

        PreferredCustomer pc = new PreferredCustomer("David Mistretta","943 Fakedale Way, Funnyvale, MO, 01337","978-000-0000","01A001");
        pc.setBalance(550);
        System.out.println("Object to input into customers.dat\n" + pc.toString() +"\n\n");
        oos.writeObject(pc);
     catch (IOException e) 
        e.printStackTrace();
    

    try (FileInputStream fis = new FileInputStream("customers.dat");
         ObjectInputStream ois = new ObjectInputStream(fis)) 

        PreferredCustomer pca = (PreferredCustomer) ois.readObject();
        System.out.println("Object output from customers.dat\n" + pca.toString());
        ois.close();
     catch (IOException | ClassNotFoundException e) 
        e.printStackTrace();
     
 

我在 Person.java 中编写的无参数构造函数(第 28 -> 34 行)

public Person() 

    System.out.println("Person no arg construct");
    m_name = "";
    m_phoneNumber = "";
    m_address = "";

电流输出

Object to input into customers.dat
Preferred Customer
Name: David Mistretta
Address: 943 Fakedale Way, Funnyvale, MO, 01337
Phone Number: 978-000-0000
Customer Number: 01A001
Mailing List: true
Balance: 550.0
Discount: 0.05


Person no arg construct
Object output from customers.dat
Preferred Customer
Name: 
Address: 
Phone Number: 
Customer Number: 01A001
Mailing List: true
Balance: 550.0
Discount: 0.05

我希望“姓名”、“地址”和“电话号码”字段在输入时反映这些字段。 我遵循了关于如何将对象存储在文件中的说明https://kodejava.org/how-do-i-store-objects-in-file/

如果有人能指出我如何处理这个问题的正确方向,我将不胜感激。

【问题讨论】:

如果这些字段在非序列化类中,它们将不会被序列化。目前尚不清楚您在这里真正要问的是什么。您当然不能以这种方式更改序列化的机制,并且不清楚为什么您认为即使可以这样做也会有所帮助。 【参考方案1】:

必须调用每个非Serializable 类的构造函数。 Java 语言禁止其他任何事情。 Java 序列化机制必须进行狡猾的字节码验证以避免构造函数。在某些类中,构造函数可能会执行某种安全检查。

但是,在 Serializable 类上的任何内容之前调用超类构造函数。所以你的问题可能在其他地方。

(注意:为了改变他们的偏好而破坏和重建人是不受欢迎的。)

【讨论】:

啊哈!谢谢你。你的评论让我明白了我忘记了我的 Person.java 类的实现 Serializible 的事实。我想我假设只有正在编写和读取的子类必须实现它。谢谢!我意识到为可变信息保存一个数据库更有意义,我只是想尝试在 .dat 文件中读取和写入对象。我在想这样做可能是一种说法,在游戏中保存过多的 NPC 对象,其中包含有关它们的特定信息?无论如何,感谢您的帮助!【参考方案2】:

所以,我忽略了在我的 Person.java 类中添加实现 Serializable。感谢 Tom Hawtin 告诉我超类构造函数在 Serializable 类上的任何内容之前被调用,这使我找到了问题的根源。因此,为了防止在从 ObjectInputStream 读取对象时对超类构造函数进行无参数调用,请确保超类正在使用 Serializable 接口。如果不是,将调用无参数构造函数。

【讨论】:

它仍然会调用最近的 non-Serializable 基类的无参数构造函数。真正的问题是您希望对不可序列化类中的数据进行序列化,这只是一个矛盾。 所以我现在意识到我只需要在 Person.java 中实现 Serializable 因为 PreferredCustomer.java 通过 Customer.java 继承自它。一个类如何是不可序列化的?据我了解,您可以序列化(或将字节流写入)到保存实例化对象状态的 .dat 文件。然后您可以通过反序列化字节流并将该对象状态加载到要访问的内存中来读取该对象(?)。 如果一个类及其任何基类或接口都没有实现/扩展Serializable,则该类是不可序列化的。在这种情况下,它不会被序列化。 @user207421 因此,当我将 implements Serializable 添加到 Person.java 时(注意:Cusomer 和 PreferredCustomer 在我的问题开始时都实现了 Serializable )它变成了一个 Serializable 类。那么,术语的矛盾在哪里呢?当您说它将调用最近的非可序列化类的无参数构造函数时,您所说的最近是什么意思?包或项目范围内的任何类?你是说如果我在同一个包中有另一个类,那么仍然会调用无参数构造函数吗?如果该类不继承自 Person.java 怎么办?

以上是关于ObjectInputStream - 读取对象 - 有没有办法阻止调用无参数超类构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

ObjectInputStream - 读取对象 - 有没有办法阻止调用无参数超类构造函数?

对象反序列化流ObjectInputStream

使用ObjectInputStream的readObject()方法如何判断读取到多个对象的结尾

使用 LocalDate 字段读取对象时自定义 ObjectInputStream 的意外行为

Android:读取arraylist时ObjectInputStream抛出ClassCastException

对象流: ObjectInputStream 和 ObjectOutputStream