Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a deserialised object the same instance as the original

Tags:

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 correctly that the object will now have a new heap address but will still be the EXACT SAME instance of the class.

like image 957
Charlie Olson Avatar asked Mar 14 '15 17:03

Charlie Olson


People also ask

What happens when you serialize and deserialize an object?

Serialization is a mechanism of converting the state of an object into a byte stream. Deserialization is the reverse process where the byte stream is used to recreate the actual Java object in memory. This mechanism is used to persist the object.

How does a deserializer work?

Deserialization is the process of reconstructing a data structure or object from a series of bytes or a string in order to instantiate the object for consumption. This is the reverse process of serialization, i.e., converting a data structure or object into a series of bytes for storage or transmission across devices.

What is meant by deserialization?

Deserialization is the opposing process which takes data from a file, stream or network and rebuilds it into an object. Serialized objects can be structured in text such as JSON, XML or YAML. Serialization and deserialization are safe, common processes in web applications.

How an object can become serializable?

To serialize an object means to convert its state to a byte stream so way that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java.


3 Answers

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.

  • All java objects are created in java heap (except for some which are kept in pool but for you question we will skip them for now).
  • When an instance of a class is created using new keyword, deserialization, clone method or reflection api's newInstance method, a new space in heap is reserved and we assign it to a object reference (the reference can be of the object's class or one of the super classes of the object's class - again we can ignore this detail for now).
  • When you save your object, the object's state is saved with all it's nested objects.
  • When you deserialize your object, the object will create a new entry in heap which will not have any references to any of the objects.

Look at the below diagram for picturizing the above concept in you context:

enter image description here

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:

enter image description here

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:

enter image description here

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 
like image 71
Anshuman Avatar answered Dec 29 '22 01:12

Anshuman


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));     } } 
like image 40
fps Avatar answered Dec 29 '22 01:12

fps


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).

like image 35
Andy Turner Avatar answered Dec 29 '22 01:12

Andy Turner