为什么在读写文件时ObjectInput / OutputStream丢失对象引用?

时间:2019-03-10 00:28:06

标签: java io stream objectinputstream objectoutputstream

我有两个可以交互的类:

存储CD,DVD,PaperMedias的架子:

 chip.chipBackgroundColor = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.yourColor))

和客户:

    public class Shelf {
        private ArrayList<CD> cds;
        private ArrayList<DVD> dvds;
        private ArrayList<PaperMedia> paperMedias;
          ...etc

物理介质是CD,DVD,PaperMedia的父级。

首先,我将初始化一些商品的货架,然后让客户借用其中的一些商品。然后,将这些对象保存到ShelfObjects.txt和CustomerObjects.txt。

当我再次从这些文件中读取这些对象时,似乎两者之间的链接丢失了,尤其是客户的PhysicalMedia与货架的PhysicalMedia之间。这些绝对应该具有相同的参考,例如,Metallica CD在架子上应具有与客户帐户中相同的参考。

因此,当我更改状态时,例如Metallica CD的状态将不会在其他来源中更新!

有没有保存此参考文献?

我通过以下方式在CustomerDatabase类中加载和保存媒体:

public class Customer implements Serializable {
    private Map<PhysicalMedia, Calendar> mediaOwned;  
    private Map<PhysicalMedia,Calendar> mediaReturned; 
    private Map<PhysicalMedia,CalendarPeriod> mediaOnHold;
     ...etc

我在Shelf类中进行类似的加载和存储。

1 个答案:

答案 0 :(得分:2)

问题是您要使用两个单独的文件和两个单独的对象序列化流来存储两个数据库。

当前方法对您不起作用的原因是对象序列化协议将对象引用存储为简单数字。它将流中的对象编号为1、2、3,依此类推,并使用这些数字来引用流中先前序列化的对象。

这在一个流的上下文中起作用。但是,当您有两个或多个流时,给定对象在每个流中可能具有不同的数字。这意味着readObject方法无法知道两个不同流中的两个对象实际上应该链接在一起。

简单的解决方案是执行以下操作:

ObjectInputStream in = new ObjectInputStream(new  FileInputStream("DB.txt"));
for (int i = 0; i < customers.size(); i++) {
    out.writeObject(customers.get(i));
}
for (int i = 0; i < shelves.size(); i++) {
    out.writeObject(shelves.get(i));
}

或者更好的是,直接序列化customersshelves列表,因为这将简化反序列化。

(是的……这弄乱了您当前的代码结构。您将不得不在同一位置加载和保存CustomerShelf数据库,或者在该位置传递开放流。 )

也可以将对象存储在两个单独的文件中,但是您需要使用自定义序列化方法来实现。

  • 首先,您需要确定要将每个共享子对象放入哪个文件;即PhysicalMedia对象是否存储在Customer数据库或Shelf数据库中?

  • 对于每个共享库类,定义适当类型的标识符字段;例如String或`long。修改您的代码库,以便在该字段中填充应用程序上下文中唯一的值。

  • 对于要用于对象驻留的数据库,请照常进行序列化。

  • 对于其他数据库,请使用“对象序列化”高级功能:

    • 写入时,将对象替换为(仅)其标识符,然后
    • 读取后,在第一个数据库中查找标识符,然后将查找的对象插入反序列化的对象中。

最后,将需要对对象序列化API,自定义序列化等有深入的了解。在您的示例中,您增加了复杂性,您要替换的对象是Map对象中的键。由于无法为标准地图类添加自定义readObjectwriteObject,因此您将需要对Stream类本身的自定义子类进行深入的技巧。 (而且...不,我不能给你一个例子!)


此外:这种事情是不建议使用对象序列化来实现数据库的原因之一。最好使用真实的数据库以及ORA技术(例如JPA)(例如Hibernate)。还有其他原因。