反序列化对象是否与原始对象相同
Is a deserialised object the same instance as the original
当我从 class 实例化一个对象时,一个对象被保存在 java 堆中。当我通过序列化保存对象并稍后反序列化对象时,我是否正确理解该对象现在将具有新的堆地址但仍将是 class.
的完全相同的实例
不,简单的答案是反序列化的对象在内存中不会是同一个实例!它将通过 http://www.javalobby.org/java/forums/t17491.html link 为 same.Also 分配新内存,其中包含使用单例反序列化检索对象的示例!还深入了解 readResolve() 方法,它将在某些方面有所帮助案例。
反序列化的实例肯定与原始实例不同,因为 deserialized != original
将始终为真。
反序列化的实例可能等于也可能不等于原始实例,如 deserialized.equals(original)
。对于 Serializable
class 的合理实现,equals
可能在反序列化后为真,但创建一个 class 并不适用:
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
时碰巧传递了零,否则 serialization/deserialization 之后的实例将不相等,因为 value
的值不会被序列化(因为它是短暂的)。
不,它们在内存中不会是同一个对象 originalObj == deserilized
将是错误的,但是 originalObj.equals(deserilized)
应该是正确的。
Objects B, C, D and E. All of them when instantiated, had Object A. Then, let's assume I serialize and deserialized all of them. When I change a field of Object A after deserialization, is there a way to reflect such change in the Object A(s) in BCDE?
如果我理解正确的话,答案是否定的,引用不会指向同一个对象 A
但是,如果您愿意,可以将每个对象 B、C、D 和 E 中对象 A 的所有引用显式设置为指向对象 A 的同一实例
这里有一个演示来说明所提出的观点。
import java.io.*;
import java.util.*;
public class Demo {
public static void main(String... aArguments) {
List<Quark> quarks = Arrays.asList(
new Quark("up"), new Quark("down")
);
serialize(quarks);
List<Quark> 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<Quark> 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<Quark> deserialize() {
List<Quark> recoveredQuarks = null;
try {
InputStream file = new FileInputStream("quarks.ser");
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream(buffer);
recoveredQuarks = (List<Quark>)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;
}
}
序列化前:
A originalA = ...;
B.a == C.a == D.a == E.a == originalA
所有 B.a
、C.a
、D.a
和 E.a
都指向 A
、originalA
.[=30 的相同引用=]
序列化和反序列化后:
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
所有 B.a
、C.a
、D.a
和 E.a
都指向 A
、otherA
.[=30 的相同引用=]
但是:
originalA != otherA
不过
originalA.equals(otherA) == true
注意: equals()
将 return true
仅当 覆盖 为 一致 根据序列化字段检查相等性。否则,它 可能 return false
.
编辑:
证明:
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();
b.a = originalA;
C c = new C();
c.a = originalA;
System.out.println("b.a == c.a is " + (b.a == c.a));
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));
}
}
您的问题不能只回答是或否。需要分析这个概念。我会建议你拿笔和纸自己做,记住以下几点。
- 所有 java 对象都在 java 堆中创建(除了一些
保存在池中,但对于你的问题,我们现在将跳过它们。
- 当使用 new 关键字创建 class 的实例时,
反序列化、克隆方法或反射api的newInstance方法,
堆中的新 space 被保留,我们将其分配给对象引用
(引用可以是对象的 class 或超类之一
classes of the object's class - 同样我们可以忽略这个细节
现在)。
- 当您保存对象时,对象的状态会连同它的所有内容一起保存
嵌套对象。
- 当您反序列化您的对象时,该对象将创建一个新条目
在堆中,不会引用任何对象。
查看下图以在您的上下文中描绘上述概念:
所有对象 A 引用都指向一个堆条目,如果您尝试 objectB.getObjectA() == objectC.getObjectA() 或任何其他此类操作,您将得到 true。
案例1当你单独保存对象并反序列化它们时,这里是堆中发生的事情:
正如您现在所知道的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 将不会 return 为真,因为对象 A 对复制对象的引用不再相同.
情况 2 相反,当您将对象保存在单个文件中并稍后反序列化它们时,堆中会发生以下情况:
正如您现在所知道的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 现在将为真,因为对象 A 副本的引用相同,但它仍然是对象的新副本答.
一个支持我推论的快速程序(案例1和案例2):
public class Test{
public static void main (String args[]) throws IOException, ClassNotFoundException{
A a = new A();
B b = new B();
b.a = a;
C c = new C();
c.a = a;
System.out.println("b.a == c.a is " + (b.a == c.a));
// 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;
}
输出如下:
b.a == c.a is true
Case 1 - bCopy.a == cCopy.a is false
Case 2 - bCopy.a == cCopy.a is true
当我从 class 实例化一个对象时,一个对象被保存在 java 堆中。当我通过序列化保存对象并稍后反序列化对象时,我是否正确理解该对象现在将具有新的堆地址但仍将是 class.
的完全相同的实例不,简单的答案是反序列化的对象在内存中不会是同一个实例!它将通过 http://www.javalobby.org/java/forums/t17491.html link 为 same.Also 分配新内存,其中包含使用单例反序列化检索对象的示例!还深入了解 readResolve() 方法,它将在某些方面有所帮助案例。
反序列化的实例肯定与原始实例不同,因为 deserialized != original
将始终为真。
反序列化的实例可能等于也可能不等于原始实例,如 deserialized.equals(original)
。对于 Serializable
class 的合理实现,equals
可能在反序列化后为真,但创建一个 class 并不适用:
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
时碰巧传递了零,否则 serialization/deserialization 之后的实例将不相等,因为 value
的值不会被序列化(因为它是短暂的)。
不,它们在内存中不会是同一个对象 originalObj == deserilized
将是错误的,但是 originalObj.equals(deserilized)
应该是正确的。
Objects B, C, D and E. All of them when instantiated, had Object A. Then, let's assume I serialize and deserialized all of them. When I change a field of Object A after deserialization, is there a way to reflect such change in the Object A(s) in BCDE?
如果我理解正确的话,答案是否定的,引用不会指向同一个对象 A
但是,如果您愿意,可以将每个对象 B、C、D 和 E 中对象 A 的所有引用显式设置为指向对象 A 的同一实例
这里有一个演示来说明所提出的观点。
import java.io.*;
import java.util.*;
public class Demo {
public static void main(String... aArguments) {
List<Quark> quarks = Arrays.asList(
new Quark("up"), new Quark("down")
);
serialize(quarks);
List<Quark> 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<Quark> 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<Quark> deserialize() {
List<Quark> recoveredQuarks = null;
try {
InputStream file = new FileInputStream("quarks.ser");
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream(buffer);
recoveredQuarks = (List<Quark>)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;
}
}
序列化前:
A originalA = ...;
B.a == C.a == D.a == E.a == originalA
所有 B.a
、C.a
、D.a
和 E.a
都指向 A
、originalA
.[=30 的相同引用=]
序列化和反序列化后:
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
所有 B.a
、C.a
、D.a
和 E.a
都指向 A
、otherA
.[=30 的相同引用=]
但是:
originalA != otherA
不过
originalA.equals(otherA) == true
注意: equals()
将 return true
仅当 覆盖 为 一致 根据序列化字段检查相等性。否则,它 可能 return false
.
编辑:
证明:
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();
b.a = originalA;
C c = new C();
c.a = originalA;
System.out.println("b.a == c.a is " + (b.a == c.a));
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));
}
}
您的问题不能只回答是或否。需要分析这个概念。我会建议你拿笔和纸自己做,记住以下几点。
- 所有 java 对象都在 java 堆中创建(除了一些 保存在池中,但对于你的问题,我们现在将跳过它们。
- 当使用 new 关键字创建 class 的实例时, 反序列化、克隆方法或反射api的newInstance方法, 堆中的新 space 被保留,我们将其分配给对象引用 (引用可以是对象的 class 或超类之一 classes of the object's class - 同样我们可以忽略这个细节 现在)。
- 当您保存对象时,对象的状态会连同它的所有内容一起保存 嵌套对象。
- 当您反序列化您的对象时,该对象将创建一个新条目 在堆中,不会引用任何对象。
查看下图以在您的上下文中描绘上述概念:
所有对象 A 引用都指向一个堆条目,如果您尝试 objectB.getObjectA() == objectC.getObjectA() 或任何其他此类操作,您将得到 true。
案例1当你单独保存对象并反序列化它们时,这里是堆中发生的事情:
正如您现在所知道的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 将不会 return 为真,因为对象 A 对复制对象的引用不再相同.
情况 2 相反,当您将对象保存在单个文件中并稍后反序列化它们时,堆中会发生以下情况:
正如您现在所知道的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 现在将为真,因为对象 A 副本的引用相同,但它仍然是对象的新副本答.
一个支持我推论的快速程序(案例1和案例2):
public class Test{
public static void main (String args[]) throws IOException, ClassNotFoundException{
A a = new A();
B b = new B();
b.a = a;
C c = new C();
c.a = a;
System.out.println("b.a == c.a is " + (b.a == c.a));
// 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;
}
输出如下:
b.a == c.a is true
Case 1 - bCopy.a == cCopy.a is false
Case 2 - bCopy.a == cCopy.a is true