在我从一个类中实例化一个对象时,该对象将保存在java堆中。当我通过序列化保存该对象并稍后对其进行反序列化时,我理解得正确吗,即该对象现在将具有新的堆地址,但仍将是该类的“完全相同”的实例。
在我从一个类中实例化一个对象时,该对象将保存在java堆中。当我通过序列化保存该对象并稍后对其进行反序列化时,我理解得正确吗,即该对象现在将具有新的堆地址,但仍将是该类的“完全相同”的实例。
你的问题的答案不能仅仅是肯定或否定。需要分析这个概念。我建议你拿起一支铅笔和纸,按照以下要点自己操作。
看下面的图表以便更好地理解上述概念:
所有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();
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
序列化之前:
A originalA = ...;
B.a == C.a == D.a == E.a == originalA
所有的B.a
、C.a
、D.a
和E.a
都指向同一个引用A
和originalA
。
经过序列化和反序列化:
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
所有的B.a
, C.a
, D.a
和E.a
指向同一个引用A
,即otherA
。
然而:
originalA != otherA
originalA.equals(otherA) == true
注意: equals()
只有在被重写以一致地基于序列化字段检查相等性时,才会返回true
。否则,它可能会返回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));
}
}
deserialized != original
始终为真。deserialized.equals(original)
。对于一个合理的可序列化类的实现,在反序列化后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;
}
}
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;
}
}