La mise en œuvre de readResolve() méthode pour Serializable Instance du Singleton
Je suis en train d'écrire un Serializable classe Singleton par l'ajout de la readResolve() la méthode. Mon intention est d'obtenir le même objet avec l'objet de l'état au moment de la sérialisation de temps.
ci-dessous est mon exemple de Test de code:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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() {
FileOutputStream fos;
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("d:\\SingletonData.txt"));
oos.writeObject(Singleton.getInstance());
} catch (FileNotFoundException e) {
e.printStackTrace();
} 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 (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (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 + "]";
}
}
De SORTIE:
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]
Je sais que le scénario actuel renverra toujours la même instance du Singleton avec le dernier Objet de l'état.
J'ai essayé en remplaçant la writeObject() et readObject() (commenté dans le présent code ci-dessus), mais ne pas obtenir le résultat souhaité.
c'est à dire
After Deserialization : Singleton [i=5]
Mais il n'y a pas de référence de ObjectInputStream dans readResolve() afin que je puisse obtenir de l'instance et de la mettre à jour l'objet sérialisé de l'état avant de revenir.
S'il vous plaît corrigez-moi si je me trompe dans ma conception, et de m'aider à résoudre ce problème.
Grâce.
OriginalL'auteur Sandy | 2013-06-30
Vous devez vous connecter pour publier un commentaire.
Voici comment elle peut être réalisée:
}
readResolve() est généralement appelé après readObject()
Une petite mise en garde, je voudrais jeter un
assertionError()
à l'intérieur du constructeur privé juste pour se prémunir contre les attaques par réflexion ou quelqu'un accidentellement l'instanciation deSingleton
à partir de l'intérieur de la classe.Le code ci-dessus viole le Singleton de la propriété, c'est à dire si vous imprimez à la fin les deux
s
ets.getInstance()
vous voyez que les deux instances existent. La faute en est à la redéfinition de l'instace
dans la méthodereadObject
. En fait, primordialreadObject
n'est pas nécessaire. La solution donnée ci-dessous par @Dorofeev est correct.OriginalL'auteur Jk1
La meilleure façon de mettre en œuvre un
Serializable
Singleton est d'utiliser un Enum.De Joshua Bloch Effectif de Java:
Vous épargner du temps et de l'utilisation d'un Enum.
Reportez-vous cette question pour plus de discussion sur le même sujet.
OriginalL'auteur Bruce Wayne
essayer cette
Noter que readResolve n'ont pas besoin d'être public.
OriginalL'auteur Evgeniy Dorofeev
La solution voté comme correcte si l'aide dans la récupération de la valeur de " i " sur l'objet désérialisé, il viole le modèle de conception singleton. Après une dé-sérialisation, deux objets de "Singleton" classe sont créés.
Preuve: modifier la méthode main() comme ci-dessous:
De sortie est:
avant de sérialisation::5 serialization.Singleton@1690726
modifié après la sérialisation::7 serialization.Singleton@1690726
après la désérialisation::5 serialization.Singleton@1662dc8
Même la deuxième proposition a le même problème.
J'ai essayé quelques autres configurations, mais rien ne marchait.
Est-il un autre moyen pour résoudre ce problème?
Veuillez étiqueter le thread avec "Singleton" ainsi, de façon à toucher une plus large audience.
Grâce.
OriginalL'auteur Kaashan
Cela devrait faire l'affaire (en fonction de votre question initiale):
Si vous souhaitez forcer le chargement du Singleton état puis définissez
obj = null
avant la désérialisation de l'état enregistré.Ou vous pouvez ajouter un
boolean
drapeau qui indique lareadResolve()
méthode si vous souhaitez conserver ou remplacerobj
.Être conscient de multi-threading questions si vous travaillez dans un environnement multi-thread.
OriginalL'auteur Frederic Leitenberger
Je crois que, tout simplement, de retourner dans la classe enfant devrait faire l'affaire
Je sais que c'est un très vieux post, mais je suis tombé sur elle et l'autre risquent de trop.
OriginalL'auteur Arijeet Chakravarty
On peut aussi faire comme ça,appelez le
getInstance()
méthode à l'intérieur d'readResolve()
et stocker le résultat dans une référence variable de typeSingleton
ensuite de retour à la référence. Assurez-vous que le type de retour de la méthode doit être deObject
type, vous pouvez fournir aucun modificateur d'accès.OriginalL'auteur Abhinav Katyayen