Un object désérialisé a-t-il la même instance que l’original?

Lorsque j’instancie un object d’une classe, un object est enregistré dans le segment de mémoire java. Lorsque je sauvegarde l’object en le sérialisant et que je le désérialise par la suite, ai-je bien compris que l’object aura désormais une nouvelle adresse de segment de mémoire mais restra toujours l’instance EXACT SAME de la classe.

La réponse à votre question ne peut pas être simplement un oui ou un non. Pour parsingr le concept est nécessaire. Je vous suggère de prendre un crayon et du papier et de le faire vous-même en gardant les points ci-dessous à l’esprit.

  • Tous les objects java sont créés dans java heap (à l’exception de certains qui sont conservés dans le pool, mais pour les questions que nous avons posées, nous les ignorerons pour l’instant).
  • Lorsqu’une instance d’une classe est créée à l’aide d’un nouveau mot clé, d’une désérialisation, d’une méthode de clonage ou de la méthode newInstance de l’API de reflection, un nouvel espace dans heap est réservé et nous l’affectons à une référence d’object (la référence peut être de la classe de l’object ou de l’un des super classes de la classe de l’object – encore une fois, nous pouvons ignorer ce détail pour le moment).
  • Lorsque vous enregistrez votre object, son état est enregistré avec tous ses objects nesteds.
  • Lorsque vous désérialisez votre object, l’object crée une nouvelle entrée dans heap qui ne contient aucune référence à aucun des objects.

Regardez le diagramme ci-dessous pour illustrer le concept ci-dessus dans votre contexte:

entrer la description de l'image ici

Toutes les références d’object A pointent vers une entrée de segment de mémoire et si vous essayez objectB.getObjectA () == objectC.getObjectA () ou toute autre opération de ce type, vous obtiendrez la valeur true.

Cas 1 Lorsque vous enregistrez les objects séparément et que vous les désérialisez, voici ce qui se passe dans le tas:

entrer la description de l'image ici

Comme vous pouvez maintenant le constater, objectBcopy.getObjectA () == objectCcopy.getObjectA () ne renverra pas la valeur true, car les références de l’object A aux objects copiés ne sont plus les mêmes.

Cas 2 Au contraire, lorsque vous enregistrez les objects dans un seul fichier et que vous les désérialisez ultérieurement, voici ce qui se passe dans le tas:

entrer la description de l'image ici

Comme vous pouvez le constater maintenant, objectBcopy.getObjectA () == objectCcopy.getObjectA () sera désormais vrai, car les références de l’object A copie sont identiques, mais il s’agit toujours d’une nouvelle copie de l’object A.

Un programme rapide pour supporter mes déductions (cas 1 et 2):

public class Test{ public static void main (Ssortingng args[]) throws IOException, ClassNotFoundException{ A a = new A(); B b = new B(); ba = a; C c = new C(); ca = a; System.out.println("ba == ca is " + (ba == ca)); // Case 1 - when two diferent files are used to write the objects FileOutputStream fout = new FileOutputStream("c:\\b.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(b); oos.close(); fout.close(); fout = new FileOutputStream("c:\\c.ser"); oos = new ObjectOutputStream(fout); oos.writeObject(c); oos.close(); fout.close(); FileInputStream fileIn = new FileInputStream("c:\\b.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); B bCopy = (B) in.readObject(); in.close(); fileIn.close(); fileIn = new FileInputStream("c:\\c.ser"); in = new ObjectInputStream(fileIn); C cCopy = (C) in.readObject(); in.close(); fileIn.close(); System.out.println("Case 1 - bCopy.a == cCopy.a is " + (bCopy.a == cCopy.a)); // Case 2 - when both the objects are saved in the same file fout = new FileOutputStream("c:\\both.ser"); oos = new ObjectOutputStream(fout); oos.writeObject(b); oos.writeObject(c); oos.close(); fout.close(); fileIn = new FileInputStream("c:\\both.ser"); in = new ObjectInputStream(fileIn); bCopy = (B) in.readObject(); cCopy = (C) in.readObject(); in.close(); fileIn.close(); System.out.println("Case 2 - bCopy.a == cCopy.a is " + (bCopy.a == cCopy.a)); } } class A implements Serializable{ } class B implements Serializable{ A a; } class C implements Serializable{ A a; } 

Avec la sortie suivante:

  ba == ca is true Case 1 - bCopy.a == cCopy.a is false Case 2 - bCopy.a == cCopy.a is true 

Avant de sérialiser:

 A originalA = ...; Ba == Ca == Da == Ea == originalA 

Tous Ba , Ca , Da et Ea la même référence de A , originalA .

Après la sérialisation et la désérialisation:

 A otherA = ...; Ba == Ca == Da == Ea == otherA 

Tous Ba , Ca , Da et Ea indiquent la même référence de A , otherA .

Toutefois:

 originalA != otherA 

bien que

 originalA.equals(otherA) == true 

Remarque: equals() ne retournera true que s’il est surchargé pour vérifier systématiquement l’ égalité en fonction des champs sérialisés. Sinon, il pourrait retourner false .


MODIFIER:

Preuve:

 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 Sample { static class A implements Serializable { private static final long serialVersionUID = 1L; } static class B implements Serializable { private static final long serialVersionUID = 1L; A a; } static class C implements Serializable { private static final long serialVersionUID = 1L; A a; } public static void main(Ssortingng args[]) throws IOException, ClassNotFoundException { A originalA = new A(); B b = new B(); ba = originalA; C c = new C(); ca = originalA; System.out.println("ba == ca is " + (ba == ca)); FileOutputStream fout = new FileOutputStream("ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(b); oos.writeObject(c); oos.close(); fout.close(); FileInputStream fileIn = new FileInputStream("ser"); ObjectInputStream in = new ObjectInputStream(fileIn); B bDeserialized = (B) in.readObject(); C cDeserialized = (C) in.readObject(); in.close(); fileIn.close(); System.out.println("bDeserialized.a == cDeserialized.a is " + (bDeserialized.a == cDeserialized.a)); } } 

Non, la réponse est simple: cet object désérialisé ne sera pas la même instance en mémoire! Il allouera une nouvelle mémoire pour le même. Passez également par le lien http://www.javalobby.org/java/forums/t17491.html qui contient un exemple de récupération d’object en utilisant la désérialisation avec singleton! ce sera utile dans certains cas.

L’instance désérialisée sera certainement une instance distincte de l’original, car en deserialized != original sera toujours vrai.

L’instance désérialisée peut être égale ou non à l’instance d’origine, comme dans deserialized.equals(original) . Pour une implémentation raisonnable d’une classe Serializable , equals sera probablement vrai après la désérialisation, mais il est sortingvial de créer une classe pour laquelle cela ne tient pas:

 class Pathological implements Serializable { transient int value; Pathological(int value) { this.value = value; } @Override public int hashCode() { return value; } @Override public boolean equals(Object other) { if (other == this) { return true; } if (other instanceof Pathological) { return ((Pathological) other).value == this.value; } return false; } } 

À moins que vous ne passiez zéro lors de la construction du Pathological , les instances ne seront pas égales après la sérialisation / désérialisation, car la valeur de value ne sera pas sérialisée (car elle est transitoire).

Non, ils ne seront pas le même object en mémoire. originalObj == deserilized sera faux, cependant originalObj.equals(deserilized) devrait être vrai.

Les objects B, C, D et E. Tous, une fois instanciés, avaient l’object A. Ensuite, supposons que je les ai tous sérialisés et désérialisés. Lorsque je modifie un champ de l’object A après la désérialisation, existe-t-il un moyen de refléter un tel changement dans le ou les objects A dans BCDE?

Si je vous ai bien compris, la réponse est non, les références ne désigneront pas le même object.

Toutefois, si vous le souhaitez, vous pouvez définir explicitement toutes les références de l’object A dans chaque object B, C, D et E pour qu’elles pointent vers la même instance de l’object A.

Voici une démo pour illustrer les points soulevés.

 import java.io.*; import java.util.*; public class Demo { public static void main(Ssortingng... aArguments) { List quarks = Arrays.asList( new Quark("up"), new Quark("down") ); serialize(quarks); List recoveredQuarks = deserialize(); System.out.println(quarks == recoveredQuarks); // false System.out.println(quarks.equals(recoveredQuarks)); // true System.out.println(quarks.get(0) == recoveredQuarks.get(0)); // false // but you can set it to the same instance recoveredQuarks.set(0, quarks.get(0)); System.out.println(quarks.get(0) == recoveredQuarks.get(0)); // true quarks.get(0).name = "Charm"; boolean b = quarks.get(0).name == recoveredQuarks.get(0).name; System.out.println(b); // true } static void serialize(List quarks) { try { OutputStream file = new FileOutputStream("quarks.ser"); OutputStream buffer = new BufferedOutputStream(file); ObjectOutput output = new ObjectOutputStream(buffer); output.writeObject(quarks); output.close(); } catch(IOException ex) { ex.printStackTrace(); } } static List deserialize() { List recoveredQuarks = null; try { InputStream file = new FileInputStream("quarks.ser"); InputStream buffer = new BufferedInputStream(file); ObjectInput input = new ObjectInputStream(buffer); recoveredQuarks = (List)input.readObject(); input.close(); } catch(ClassNotFoundException ex){ } catch(IOException ex){ ex.printStackTrace(); } return recoveredQuarks; } } class Quark implements Serializable { Ssortingng name; Quark(Ssortingng name) { this.name = name; } @Override public boolean equals(Object o) { if (o != null && o instanceof Quark) { return this.name.equals(((Quark)o).name); } return false; } }