我有两个相互作用的类:
货架,存放CD,DVD,PaperMedias:
public class Shelf {
private ArrayList<CD> cds;
private ArrayList<DVD> dvds;
private ArrayList<PaperMedia> paperMedias;
...etc
和客户:
public class Customer implements Serializable {
private Map<PhysicalMedia, Calendar> mediaOwned;
private Map<PhysicalMedia,Calendar> mediaReturned;
private Map<PhysicalMedia,CalendarPeriod> mediaOnHold;
...etc
物理媒体是CD,DVD,PaperMedia的父母。
首先,我将使用一些物品初始化货架,并且客户借用一些这些物品。然后我将这些对象保存到ShelfObjects.txt和CustomerObjects.txt。
当我再次从这些文件中读取这些对象时,似乎两者之间的链接丢失了,特别是在客户的PhysicalMedia和架子的PhysicalMedia之间。这些应该具有相同的参考,例如Metallica CD应该在Shelf中具有与Customer帐户中相同的引用。
因此,当我更改说Metallica CD的状态时,它不会在其他来源中更新它!
有没有保留这个参考?
我在CustomerDatabase类中以下列方式加载和保存媒体:
public class CustomersDatabase implements Serializable {
private ArrayList<Customer> customers = new ArrayList<Customer>();
//etc..
public void load() {
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("CustomersObject.txt"));
try {
customers.clear();
while(true) {
customers.add((Customer)in.readObject());
}
} catch (ClassNotFoundException e) {
System.out.println("Customer class in file wasn't found");
}
in.close();
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
} catch (IOException e) {
System.out.println("\n^ Customer load successful\n");
}
public void save() {
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("CustomersObject.txt",false));
for (int i=0;i<customers.size();i++) {
out.writeObject(customers.get(i));
}
out.close();
System.out.println("\nCustomer save successful\n");
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
} catch (IOException e) {
System.out.println("IO exception ");
e.printStackTrace();
}
}
我在Shelf类中做类似的加载和存储。
问题是您使用两个单独的对象序列化流使用两个单独的文件存储两个数据库。
您当前的方法不适合您的原因是对象序列化协议将对象引用存储为简单数字。它将流中的对象编号为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));
}
或者更好的是,直接序列化customers
和shelves
列表,因为这将简化反序列化。
(是的......这会弄乱你当前的代码结构。你必须在同一个地方加载并保存Customer
和Shelf
数据库,或者在这个地方传递一个开放的流。)
也可以将对象存储在两个单独的文件中,但您需要使用自定义序列化方法来执行此操作。
PhysicalMedia
对象是否存储在Customer
数据库或Shelf
数据库中?String
或`long。修改您的代码库,以便使用在应用程序上下文中唯一的值填充该字段。最后一项需要深入了解对象序列化API,自定义序列化等。在您的示例中,您要增加的复杂性是要替换的对象是Map
对象中的键。由于您无法为标准地图类添加自定义readObject
和writeObject
,因此您需要在Stream类本身的自定义子类中执行深层技巧。 (而且......不,我不能举个例子!)
旁白:这种事情是使用对象序列化来实现数据库的不可取的原因之一。最好使用真正的数据库和ORM技术,如JPA(例如Hibernate)。还有其他原因。