Java 为什么在序列化/反序列化的情况下只创建一个父对象

Java 为什么在序列化/反序列化的情况下只创建一个父对象,java,serialization,deserialization,Java,Serialization,Deserialization,为什么在序列化/反序列化的情况下只创建一个父对象 //superclass A //A class doesn't implement Serializable //interface. class A { int i; // parameterized constructor public A(int i) { this.i = i; } // default constructor public A()

为什么在序列化/反序列化的情况下只创建一个父对象

//superclass A 
//A class doesn't implement Serializable
//interface.
class A 
{
    int i;

    // parameterized constructor
    public A(int i)
    {
        this.i = i;
    }

    // default constructor
    public A()
    {
        i = 50;
        System.out.println("A's class constructor called");
    }
}

// subclass B implementing Serializable interface
class B extends A implements Serializable
{
    int j;

    public B(int i, int j)
    {
        super(i);
        System.out.println("B.B()");
        this.j = j;
    }
}

// Driver class
public class SerializationWithInheritanceExample
{
    public static void main(String[] args) throws Exception
    {
        B b1 = new B(10, 20);

        System.out.println("i = " + b1.i);
        System.out.println("j = " + b1.j);

        // Serializing B's(subclass) object
        try (FileOutputStream fos = new FileOutputStream("abc.ser");
                ObjectOutputStream oos = new ObjectOutputStream(fos))
        {
            // Method for serialization of B's class object
            oos.writeObject(b1);
        }

        System.out.println("Object has been serialized\n");

        // Reading the object from a file
        readObject();
        readObject();
        readObject();

    }

    static void readObject()
    {
        // Reading the object from a file
        try (FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis))
        {
            // Method for de-serialization of B's class object
            B b2 = (B) ois.readObject();

            System.out.println("HasCode of A:"+ b2.getClass().getSuperclass().hashCode() +" | HasCode of B:"+b2.hashCode());

            System.out.println("i = " + b2.i);
            System.out.println("j = " + b2.j);
        } catch (IOException | ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}
输出

B.B()
i = 10
j = 20
Object has been serialized

A's class constructor called
HasCode of A:1311053135 | HasCode of B:1705736037
i = 50
j = 20
A's class constructor called
HasCode of A:1311053135 | HasCode of B:455659002
i = 50
j = 20
A's class constructor called
HasCode of A:1311053135 | HasCode of B:250421012
i = 50
j = 20
在多次反序列化B的对象时,只创建一个A类父对象。
为什么只创建一个对象?

您不是在调用
A
实例的
hashCode()
方法,而是在类
A
中,在大多数情况下,类对象只有一个实例

让我们把它分解一下:

b2               // instance of B
.getClass()      // Class<B>
.getSuperclass() // Class<A>
.hashCode()      // hash code of Class<A>
b2//B的实例
.getClass()//类
.getSuperclass()//类
.hashCode()//类的哈希代码
甚至不可能为
B
实例的“部分
a
”获取单独的哈希代码:只有一个对象,它只有一个哈希代码


当你创建一个
B
时,只会创建一个对象,而不是像你想象的那样创建两个。此对象包含所有
B
,其中包括
A

的部分。在A的情况下,您得到A类的hashcodeA。在B的情况下,您得到实例的hashcodeB。并且您的3个B实例共享1个超类A(与类B一起)。因此,例如,如果您调用
b2.getClass().hashcode()
三次,那么所有这些方法调用的输出也将相等,因为您有一个类B。

当您调用
b2.getClass().getSuperclass()
时,您有一个类型为
class
的实例。这是类A的唯一对象,它包含有关类
A
声明的信息。当您调用
b2.hashCode()
时,您有实例的哈希代码,它引用了
b2

为什么说“只创建了一个A类父对象”是因为A的哈希代码被打印出来了吗?如果是,请重新检查代码。。这是类的哈希代码,而不是对象的哈希代码。JVM只会将一个对象类的一个实例加载到每个类加载器的内存中。您应该使用B的哈希代码作为每次加载A的证据。感谢@ChrisK的解释。“只创建了一个A类父对象”显然是错误的。这些痕迹表明创建了三个。您的问题没有意义。@EJP Yes我的理解是错误的。这个答案可以通过解释为什么只为B创建一个对象来改进。下面的链接解释了相互扩展的对象的JVM内存布局。关键在于,在内存中,B由B和A在单个内存序列中的串联表示。