When I instantiate an object from a class, an object is saved in the java heap. When I save the object by serializing it and I later deserialize the object, do I understand corr
No,Simple answer is that deserialized object will not be the same instance in memory ! It will allocate new memory for same.Also go through http://www.javalobby.org/java/forums/t17491.html link which contains example of retrieving object using deserialization with singleton !Also go through readResolve() method in depth, it will be helpful in some cases.
The answer to your question cannot be just a yes or no. To analyze the concept is required. I will suggest you to take a pencil and paper and do it yourself keeping the below points in mind.
Look at the below diagram for picturizing the above concept in you context:
All the object A references are pointing to one heap entry and if you try objectB.getObjectA() == objectC.getObjectA() or any other such operation, you will get true.
Case 1 When you save the objects separately and deserialize them here is what happens in the heap:
As you can figure out now that objectBcopy.getObjectA() == objectCcopy.getObjectA() will not return true as the references of object A for the copied objects are no more same.
Case 2 On the contrary, when you save the objects in a single file and deserialize them later, here is what happens in the heap:
As you can figure out now that objectBcopy.getObjectA() == objectCcopy.getObjectA() will now be true as the references of object A copy are same, but that's still a new copy of object A.
A quick program to support my deductions (Case 1 and Case 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;
}
With the following output:
b.a == c.a is true
Case 1 - bCopy.a == cCopy.a is false
Case 2 - bCopy.a == cCopy.a is true
The deserialized instance will definitely be a distinct instance from the original, as in deserialized != original
will always be true.
The deserialized instance may or may not be equal to the original instance, as in deserialized.equals(original)
. For a reasonable implementation of a Serializable
class, equals
probably will be true after deserialization, but it is trivial to create a class for which this does not hold:
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;
}
}
Unless you happen to pass zero when constructing the Pathological
, the instances won't be equal after serialization/deserialization, since the value of value
won't be serialized (as it is transient).
Before serializing:
A originalA = ...;
B.a == C.a == D.a == E.a == originalA
All B.a
, C.a
, D.a
and E.a
point to the same reference of A
, originalA
.
After serializing and deserializing:
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
All B.a
, C.a
, D.a
and E.a
point to the same reference of A
, otherA
.
However:
originalA != otherA
though
originalA.equals(otherA) == true
Note: equals()
will return true
only if it is overriden to consistently check equality based on serialized fields. Otherwise, it might return false
.
EDIT:
Proof:
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));
}
}
No they will not be the same object in memory originalObj == deserilized
will be false, however originalObj.equals(deserilized)
should be true.
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?
If I understand you correctly the answer is no, the references will not be pointing to the same Object A
However if you so desire you can explicitly set all of the references of Object A in each object B, C, D and E to point to the same instance of Object A
Here is a demo to illustrate the points made.
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;
}
}