java - 如何在序列化中获得相同的引用?

标签 java serialization reference

这是我使用可序列化接口(interface)的部分。当我启动程序时,它将为每个列表创建相同的对象,但具有不同的引用。有什么办法可以将它们全部作为一个引用吗?

private static void quitApplication(){
    System.out.println("Stopping the system...\n");
    ///store all the objects by serializing
    try {
        FileOutputStream fileOut2 = new FileOutputStream("FlightList.ser");
        ObjectOutputStream out2 = new ObjectOutputStream(fileOut2);
        out2.writeObject(Flight.getFlights());
        out2.close();
        fileOut2.close();
    }catch(IOException i) {
        System.out.println("FlightList.ser ERROR");
    }

    try {
        FileOutputStream fileOut = new FileOutputStream("CityList.ser");
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(City.getCityList());
        out.close();
        fileOut.close();
    }catch(IOException i) {
        System.out.println("CityList.ser ERROR");
    }

    try {
        FileOutputStream fileOut1 = new FileOutputStream("GrapghL.ser");
        ObjectOutputStream out1 = new ObjectOutputStream(fileOut1);
        out1.writeObject(Test.flightGraph);
        out1.close();
        fileOut1.close();
    }catch(IOException i) {
        System.out.println("GrapghL.ser ERROR");
    }
    System.out.println("Done...Thank You For using the Airlines System");
    }

private static void initializeData(){
    try {
        FileInputStream fileIn = new FileInputStream("CityList.ser");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        City.setCityList((MyList<City>) in.readObject());   
        in.close();
        fileIn.close();
    }catch(Exception i){
        System.out.println("CityList.ser ERROR");
    }

    try {
        FileInputStream fileIn2 = new FileInputStream("FlightList.ser");
        ObjectInputStream in2 = new ObjectInputStream(fileIn2);
        Flight.setFlights((MyList<Flight>) in2.readObject());   
        in2.close();
        fileIn2.close();

    }catch(Exception i){
        System.out.println("FlightList.ser ERROR");
    }

    try {
        FileInputStream fileIn1 = new FileInputStream("GrapghL.ser");
        ObjectInputStream in1 = new ObjectInputStream(fileIn1);
        Test.flightGraph = (DefaultDirectedWeightedGraph<City, DefaultWeightedEdge>) in1.readObject();  
        in1.close();
        fileIn1.close();

    }catch(Exception i){
        System.out.println("GrapghL.ser ERROR");
    }
}

最佳答案

实际上有一个official Java-tutorial对此。正如 EJP 所提到的,您实现了 readResolve()。

我为 Java 1.6+ 重写了示例类:;-)

导入 java.io.ObjectStreamException; 导入 java.io.Serializable; 导入 java.util.HashMap; 导入 java.util.Map;

public class RememberMe implements Serializable {

    /**
     * Contains all known instances by id. If you feel the need to permanently discard an object you have to remove it from this Map.
     */
    static final Map<Integer, RememberMe> knownInstances = new HashMap<Integer, RememberMe>();

    /**
     * There is always only one object by this id reachable
     */
    private final int    id;
    /**
     * A changeable field
     */
    private       String name;
    /**
     * Another changeable field
     */
    private       String location;

    /**
     * Private constructor so we can ship existing instances
     */
    private RememberMe(final int id, final String name, final String location) {
        this.id = id;
        this.name = name;
        this.location = location;
    }

    /**
     * This is how you create and access objects of this class. name and location are ignored if an id already exists
     */
    public static RememberMe getRememberMe(int id, String name, String location) {
        synchronized (knownInstances) {
            final RememberMe oldValue = knownInstances.get(id);
            if(oldValue != null) {
                return oldValue;
            } else {
                final RememberMe newValue = new RememberMe(id, name, location);
                knownInstances.put(id, newValue);
                return newValue;
            }
        }
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    /**
     * This function is called after the Object is fully created (i.e. after constructor was called and all objects
     * referenced by field have been created). Now we only need to decide if it is the first of it's kind or we already
     * know an object by that id.
     */
    private Object readReplace() throws ObjectStreamException {
        synchronized (knownInstances) {
            final RememberMe oldValue = knownInstances.get(id);
            if(oldValue != null) {
                return oldValue;
            } else {
                knownInstances.put(id, this);
                return this;
            }
        }
    }
}

这是如何运作的?

  • 有一张 map 知道该类的所有实例
  • 如果对象被反序列化,我们使用 readReplace() 将其替换为之前使用相同 ID 创建的任何实例。

您需要注意,在创建对象期间,对象不会在任何地方注册自己,因为这些引用不会被 readReplace() 更改;因此,该类在 getRememberMe 中的 knownInstances 中注册,而不是在构造函数中注册!

如果您希望能够让 GC 回收此类的对象,您可能需要用一些 Weak*-variant 替换 HashMap 或其值。

关于java - 如何在序列化中获得相同的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20654581/

相关文章:

java - 使用 { } 分割大块代码以提高代码可读性 - 好的做法?

c# - Protobuf.NET 使用

c# - 如何在没有\/Date的情况下格式化JSON日期?

c# - 将对象的引用传递给新线程

java - 固定尺寸 Swing GUI 在使用不同分辨率时发生变化

java - 可选的多对一与 hibernate

java - Easymock 通用匹配器在 Eclipse 中编译错误,但可以通过 ant 构建

c# - 在 .NET 中通过线路移动对象时哪种方法最有效?

java - 关于垃圾收集和引用

javascript - 如何使 Node.js MongoDB 遵循对象引用?