反序列化对象与原始对象的实例相同

当我从类中实例化一个对象时,一个对象被保存在java堆中。 当我通过序列化保存对象并稍后反序列化对象时,我是否正确理解该对象现在将具有新的堆地址但仍将是该类的EXACT SAME实例。

你的问题的答案不能只是肯定或否定。 要分析这个概念。 我会建议你拿一支铅笔和纸,自己做,记住以下几点。

  • 所有java对象都是在java堆中创建的(除了一些保存在池中但对你来说问题我们现在将跳过它们)。
  • 当使用new关键字,反序列化,克隆方法或reflectionapi的newInstance方法创建类的实例时,会保留堆中的新空间并将其分配给对象引用(引用可以是对象的类或其中一个对象类的超类 – 我们现在再次可以忽略这个细节)。
  • 保存对象时,对象的状态将与其所有嵌套对象一起保存。
  • 反序列化对象时,该对象将在堆中创建一个新条目,该条目不会引用任何对象。

请查看下图,以便在您的上下文中概述上述概念:

在此处输入图像描述

所有对象A引用都指向一个堆条目,如果您尝试objectB.getObjectA()== objectC.getObjectA()或任何其他此类操作,您将获得true。

情况1当您单独保存对象并反序列化它们时,堆中会发生什么:

在此处输入图像描述

现在你可以弄清楚objectBcopy.getObjectA()== objectCcopy.getObjectA()不会返回true,因为复制对象的对象A的引用不再相同。

情况2相反,当您将对象保存在单个文件中并在以后反序列化时,以下是堆中发生的情况:

在此处输入图像描述

现在您可以弄清楚objectBcopy.getObjectA()== objectCcopy.getObjectA()现在将为true,因为对象A副本的引用是相同的,但它仍然是对象A的新副本。

一个支持我的扣除的快速计划(案例1和案例2):

public class Test{ public static void main (String 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; } 

使用以下输出:

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

在序列化之前:

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

所有BaCaDaEa指向AoriginalA的相同参考。

序列化和反序列化后:

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

所有BaCaDaEa指向AotherA的相同参考。

然而:

 originalA != otherA 

虽然

 originalA.equals(otherA) == true 

注意:只有在重写始终根据序列化字段检查相等性时, equals()才会返回true 。 否则,它可能会返回false


编辑:

certificate:

 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(String 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)); } } 

不,简单的回答是反序列化的对象在内存中不会是同一个实例! 它将为同一个分配新内存。还要浏览http://www.javalobby.org/java/forums/t17491.html链接,其中包含使用单例反序列化检索对象的示例!还要深入了解readResolve()方法,在某些情况下它会有所帮助。

反序列化的实例肯定是原始的一个独特的实例,如deserialized != original将永远为真。

反序列化的实例可能与原始实例相同或不同,如deserialized.equals(original) 。 对于Serializable类的合理实现,在反Serializable之后equals可能是真的,但创建一个不适用的类是微不足道的:

 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; } } 

除非在构造Pathological时碰巧传递零,否则序列化/反序列化后实例将不相等,因为值的value不会被序列化(因为它是瞬态的)。

不,他们不会是内存中的同一个对象originalObj == deserilized将是假的,但originalObj.equals(deserilized)应该是真的。

对象B,C,D和E.它们在实例化时都有对象A.然后,我们假设我对它们进行了序列化和反序列化。 当我在反序列化后更改对象A的字段时,有没有办法在BCDE中的对象A中反映这种变化?

如果我理解你的答案是肯定的,那么引用将不会指向相同的对象A.

但是,如果您愿意,可以在每个对象B,C,D和E中显式设置对象A的所有引用,以指向对象A的相同实例

这是一个演示来说明所提出的观点。

 import java.io.*; import java.util.*; public class Demo { public static void main(String... 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 { String name; Quark(String 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; } }