gpt4 book ai didi

java - 如何使用父类(super class)构造函数创建子类的实例?

转载 作者:搜寻专家 更新时间:2023-11-01 03:16:21 24 4
gpt4 key购买 nike

显然,Java 序列化机制以某种方式设法使用父类(super class)构造函数创建子类的实例。我想知道,这怎么可能?

这是一个 test这证明了这一点:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.MessageFormat;

public class Test {

public static class A {
public final int a;

public A() {
this.a = 0;
System.out.println(
MessageFormat.format(
"new A() constructor is called to create an instance of {0}.",
getClass().getName()));
}

public A(int a) {
this.a = a;
System.out.println(
MessageFormat.format(
"new A(int) constructor is called to create an instance of {0}.",
getClass().getName()));
}
}

public static class B extends A implements Serializable {
public final int b;

public B(int a, int b) {
super(a);
this.b = b;
System.out.println(
MessageFormat.format(
"new B(int, int) constructor is called to create an instance of {0}.",
getClass().getName()));
}

@Override
public String toString() {
return "B [a=" + a + ", b=" + b + "]";
}


}

public static void main(String[] args) throws Exception {

B b1 = new B(10,20);

System.out.println(b1);

ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(b1);
}

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
B b2 = (B)ois.readObject();
System.out.println(b2);
}
}
}

输出:

new A(int) constructor is called to create an instance of Test$B.
new B(int, int) constructor is called to create an instance of Test$B.
B [a=10, b=20]
new A() constructor is called to create an instance of Test$B.
B [a=0, b=20]

(您可以 try it out live on Ideone )。

如您所见,A() 构造函数在反序列化期间被调用以生成 B 的实例。在引擎盖下,这是在 ObjectStreamClass.newInstance() 中调用的,实例是由 Constructor.newInstance() 调用创建的。在调试器中,构造函数 consTest$A():

Screenshot from the the debugger showing that <code>cons</code> is <code>Test$A()</code>

在调试器中退出,创建的对象最终从 ObjectInputStream.readObject(...) 返回,并且毫无问题地转换为 B

因此,如果我没记错的话,似乎使用了 A() 构造函数(通过反射)来创建 B 的实例。

我想知道这怎么可能。

最佳答案

我怀疑构造函数 cons 一定有问题。而且我找到了A的普通构造函数被更改为B可序列化构造函数的位置。

首先,我查看了 cons 的第一个设置位置。在序列化的情况下,这是 ObjectStreamClass 的构造函数:

if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl); //here
...

所以我单步执行并在 ObjectStreamClass.getSerializableConstructor 中找到:

Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
...
cons = reflFactory.newConstructorForSerialization(cl, cons); //this does change
cons.setAccessible(true);
return cons;

cons.newInstance() 上放置调试监视

  • 在标记行 => 之前键入 A
  • 在标记行 => 之后输入 B

也就是说,用于序列化的构造函数不是A的普通构造函数,而是修改后的序列化构造函数,适配final类。

关于java - 如何使用父类(super class)构造函数创建子类的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49843291/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com