Является ли десериализованный объект тем же экземпляром, что и оригинал
Когда я создаю экземпляр объекта из класса, объект сохраняется в куче java. Когда я сохраняю объект, сериализуя его, а позже десериализую объект, правильно ли понимаю, что у объекта теперь будет новый адрес кучи, но все равно будет ТОЧНЫМ экземпляром класса.
Ответы
Ответ 1
Ответ на ваш вопрос не может быть просто да или нет. Для анализа концепции требуется. Я предлагаю вам взять карандаш и бумагу и сделать это сам, не забывая о нижеследующих моментах.
- Все java-объекты создаются в java-куче (кроме некоторых, которые
хранится в пуле, но для вас вопрос, мы пропустим их пока).
- Когда экземпляр класса создается с использованием нового ключевого слова,
десериализация, метод клона или отражение api newInstance метод,
новое пространство в куче зарезервировано, и мы присваиваем его ссылке на объект
(ссылка может быть класса объекта или одного из супер
классы класса объектов - снова мы можем игнорировать эту деталь для
в настоящее время).
- Когда вы сохраняете свой объект, состояние объекта сохраняется со всеми его
вложенных объектов.
- При десериализации объекта объект создаст новую запись
в куче, которая не будет иметь никаких ссылок на какие-либо объекты.
Посмотрите на приведенную ниже диаграмму для иллюстрации вышеуказанной концепции в вашем контексте:
![enter image description here]()
Все ссылки на объект A указывают на одну запись кучи, и если вы попытаетесь objectB.getObjectA() == objectC.getObjectA() или любую другую такую операцию, вы получите правду.
Случай 1 Когда вы сохраняете объекты отдельно и десериализуете их, вот что происходит в куче:
![enter image description here]()
Как вы теперь можете понять, что objectBcopy.getObjectA() == objectCcopy.getObjectA() не вернет true, поскольку ссылки на объект A для скопированных объектов уже не такие.
Случай 2. Наоборот, когда вы сохраняете объекты в одном файле и десериализуете их позже, вот что происходит в куче:
![enter image description here]()
Как вы теперь можете понять, что objectBcopy.getObjectA() == objectCcopy.getObjectA() теперь будет истинным, так как ссылки объекта копируются одинаково, но это еще новая копия объекта А.
Быстрая программа для поддержки моих вычетов (случай 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
Ответ 2
Перед сериализацией:
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
.
EDIT:
Доказательство:
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));
}
}
Ответ 3
Нет. Простой ответ заключается в том, что десериализованный объект не будет тем же самым экземпляром в памяти! Он будет выделять новую память для этого же. Также перейдите по ссылке http://www.javalobby.org/java/forums/t17491.html, которая содержит пример извлечения объекта с помощью десериализации с помощью singleton! Также перейдите через readResolve ( ) в глубину, в некоторых случаях это будет полезно.
Ответ 4
десериализованный экземпляр определенно будет отличным экземпляром от оригинала, так как в deserialized != original
всегда будет true.
Депериализованный экземпляр может быть или не быть равным исходному экземпляру, как в deserialized.equals(original)
. Для разумной реализации класса 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
не будет сериализовано (поскольку оно является временным).
Ответ 5
Нет, они не будут тем же самым объектом в памяти originalObj == deserilized
будет ложным, однако originalObj.equals(deserilized)
должен быть правдой.
Объекты B, C, D и E. Все из них при создании экземпляра имели объект A. Тогда допустим, что я сериализую и десериализую их все. Когда я изменяю поле Object A после десериализации, есть ли способ отразить такое изменение в объекте A (s) в BCDE?
Если вы правильно поняли, что ответ отрицательный, ссылки не будут указывать на один и тот же объект A
Однако, если вы так желаете, вы можете явно указать все ссылки объекта A в каждом объекте B, C, D и E, чтобы указать на тот же экземпляр объекта 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;
}
}