8

readResolve() メソッドを追加して、Serializable Singleton クラスを作成しようとしています。私の意図は、シリアル化時のオブジェクトの状態で同じオブジェクトを取得することです。

以下は私のテスト例のコードです:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SingletonDemo {

    public static void main(String[] args) {
          Singleton obj = Singleton.getInstance();
          System.out.println("After NEW Object creation : " + obj);

          obj.i = 5;
          System.out.println("Object modified");
          System.out.println("After Object 1st Modification : " + obj);

          serializeMe();
          System.out.println("Serialized successfully with object state : " + obj);

          obj.i = 10;
          System.out.println("Object modified again");
          System.out.println("After Object 2nd Modification : " + obj);

          Singleton st = (Singleton)deSerializeMe();
          System.out.println("Deserialized successfully");

          System.out.println("After Deserialization : " + st);
    }
    
    public static void serializeMe() {
    ObjectOutputStream oos = null;

    try {
        oos = new ObjectOutputStream(new FileOutputStream("d:\\SingletonData.txt"));
        oos.writeObject(MySerializedSingleton.getInstance());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static Object deSerializeMe() {
    ObjectInputStream oin = null;
    Object obj = null;

    try {
        oin = new ObjectInputStream(new FileInputStream("d:\\SingletonData.txt"));
        obj = oin.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();

    }
    return obj;
}

}

class Singleton implements Serializable {
   int i;
   private static Singleton obj = null;

   private Singleton() {
      System.out.println("Executing constructor");
      i=1;
   }

   public static Singleton getInstance() {
      if(obj == null) {
         obj = new Singleton();
      }
      System.out.println("An instance is returned");
      return obj;
   }

   /*private void writeObject(ObjectOutputStream oos) {
   try {
       oos.writeInt(i);
   } catch (Exception e) {
       e.printStackTrace();
   }
   }

   private void readObject(ObjectInputStream ois) {
   try {
       i = ois.readInt();
   } catch (Exception e) {
       e.printStackTrace();
   }
   }*/

   public Object readResolve() {
      System.out.println("Executing readResolve");
      return Singleton.getInstance(); // FIXME
   }

   @Override
   public String toString() {
      return "Singleton [i=" + i + "]";
   }
}

出力:

Executing constructor
An instance is returned
After NEW Object creation : Singleton [i=1]
Object modified
After Object 1st Modification : Singleton [i=5]
An instance is returned
Serialized successfully with object state : Singleton [i=5]
Object modified again
After Object 2nd Modification : Singleton [i=10]
Executing readResolve
An instance is returned
Deserialized successfully
After Deserialization : Singleton [i=10]

現在のシナリオでは常に、最新のオブジェクトの状態を持つ Singleton の同じインスタンスが返されることを知っています。

writeObject() と readObject() (上記のコードでコメント) をオーバーライドしようとしましたが、目的の結果が得られませんでした。すなわち

After Deserialization : Singleton [i=5]

しかし、readResolve() には ObjectInputStream の参照がないため、インスタンスを取得して、返す前にシリアル化されたオブジェクトの状態で更新できます。

私の概念が間違っている場合は修正して、これを解決するのを手伝ってください。

ありがとう。

4

7 に答える 7

14

これを達成する方法は次のとおりです。

public class Singleton implements Serializable {

private static Singleton instance = new Singleton();
private int i;

public static Singleton getInstance() {
    return instance;
}

private Singleton() {
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    instance = this;
}

private Object readResolve()  {
    return instance;
}

public static void main(String[] args) throws Throwable {

    Singleton s = Singleton.getInstance();
    s.i = 5;

    ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
    ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
    oos.writeObject(getInstance());
    oos.close();

    s.i = 7; //modified after serialization

    InputStream is = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(is);
    Singleton deserialized = (Singleton) ois.readObject();
    System.out.println(deserialized.i);  // prints 5
}

}

于 2013-06-30T05:44:11.137 に答える
3

これを試して

   Object readResolve() {
      Singleton s = getInstance();
      s.i = i;
      return s;
   }

readResolve はパブリックである必要はないことに注意してください。

于 2013-06-30T06:05:34.707 に答える
0

これでうまくいくはずです(最初の質問に基づいて):

   public Object readResolve() {
      System.out.println("Executing readResolve");
      if (obj == null) // optionally use external boolean flag to control this
      {
          System.out.println("readResolve - assigned obj = this - loaded state");
          obj = this;
      }
      return Singleton.getInstance();
   }

シングルトン状態を強制的にロードする場合はobj = null、保存された状態を逆シリアル化する前に設定します。

または、保持するかオーバーライドするかをメソッドbooleanに伝えるフラグを追加することもできます。readResolve()obj

マルチスレッド環境で作業している場合は、マルチスレッドの問題に注意してください。

于 2016-06-29T15:39:00.393 に答える
0

子クラスでこれを返すだけでうまくいくと思います

   public Object readResolve() {
      System.out.println("Executing readResolve");
      return this; 
   }

私はそれが非常に古い投稿であることを知っていますが、私はそれに出くわしました。

于 2018-04-23T09:20:39.700 に答える