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

use*_*061 5 java serialization reference

这是我使用serialisable接口的部分.当我启动程序时,它将为每个列表创建相同的对象,但具有不同的引用.有没有办法把它们作为一个参考?

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

The*_*tor 0

实际上有一个关于此的官方 Java 教程。正如 EJP 所提到的,您实现了 readResolve()。

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

导入 java.io.ObjectStreamException; 导入 java.io.Serialized; 导入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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?

  • 有一个映射知道该类的所有实例
  • 如果一个对象被反序列化,我们会用readReplace()之前使用相同 id 创建的任何实例来替换它。

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

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