反序列化对象是否与原始对象的实例相同

2022-09-02 03:48:04

当我从类中实例化对象时,一个对象保存在java堆中。当我通过序列化对象来保存对象,然后反序列化对象时,我是否正确地理解该对象现在将具有新的堆地址,但仍将是该类的完全相同的实例。


答案 1

您的问题的答案不能只是“是”或“否”。分析概念是必需的。我会建议你拿一支铅笔和纸,自己做,记住以下几点。

  • 所有java对象都是在java堆中创建的(除了一些保存在池中的对象,但对于您的问题,我们现在将跳过它们)。
  • 当使用new关键字,反序列化,克隆方法或反射API的newInstance方法创建类的实例时,堆中的新空间被保留,我们将其分配给对象引用(引用可以是对象的类或对象类的超类之一 - 再次我们可以暂时忽略此详细信息)。
  • 保存对象时,对象的状态将与所有嵌套对象一起保存。
  • 反序列化对象时,该对象将在堆中创建一个新条目,该条目不会对任何对象进行任何引用。

请看下图,在您的上下文中描绘上述概念:

enter image description here

所有对象 A 引用都指向一个堆条目,如果您尝试 objectB.getObjectA() == objectC.getObjectA() 或任何其他此类操作,您将获得 true。

案例1当您单独保存对象并反序列化它们时,堆中会发生什么情况:

enter image description here

正如你现在所发现的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 不会返回 true,因为对象 A 对复制对象的引用不再相同。

案例 2相反,当您将对象保存在单个文件中并在以后反序列化它们时,以下是堆中发生的情况:

enter image description here

正如你现在所知道的,objectBcopy.getObjectA() == objectCcopy.getObjectA() 现在将是正确的,因为对象 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

答案 2

序列化之前:

A originalA = ...;
B.a == C.a == D.a == E.a == originalA

所有 、 和 都指向 、 的同一引用。B.aC.aD.aE.aAoriginalA

序列化和反序列化之后:

A otherA = ...;
B.a == C.a == D.a == E.a == otherA

所有 、 和 都指向 、 的同一引用。B.aC.aD.aE.aAotherA

然而:

originalA != otherA

虽然

originalA.equals(otherA) == true

注意:仅当它被覆盖以基于序列化字段一致地检查相等性时才会返回。否则,它可能会返回 。equals()truefalse


编辑:

证明:

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));
    }
}