Is a deserialised object the same instance as the original

前端 未结 5 1888
心在旅途
心在旅途 2021-02-04 02:07

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

相关标签:
5条回答
  • 2021-02-04 02:10

    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.

    0 讨论(0)
  • 2021-02-04 02:13

    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
    
    0 讨论(0)
  • 2021-02-04 02:25

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

    0 讨论(0)
  • 2021-02-04 02:28

    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));
        }
    }
    
    0 讨论(0)
  • 2021-02-04 02:34

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题