我对反射有丰富的经验。首先是一些示例代码:
public abstract class A {
public A () {
init();
}
public abstract void init ();
}
public class B extends A {
private int i = 0;
public B () {
super();
System.out.println(i);
}
public void init () {
i = 1;
}
}
在我的代码中的某处,我使用反射 api 来实例化对象 B。
Class<AbstractSection> bc = (Class<AbstractSection>) Class.forName(B);
Constructor<?> bcon = bc.getConstructor();
B b = (B) bcon.newInstance();
我期望的是 B 的一个实例,其中变量 i 设置为值“1”。我得到的是 B 的一个实例,我仍然设置为“0”。 通过调试器仔细观察,我发现这并不完全正确:i 仍未设置为“0”。它在中更改为“1” init() 方法并在 super() 调用返回的那一刻设置回“0”。
有人知道吗?提前致谢,
曼纽尔
PS:我知道我可以通过不在父类(super class)中而是在继承构造函数中调用 init() 来解决这个问题。
最佳答案
对于初学者来说,这与反射无关 - 如果您自己实例化该类,您会得到相同的结果。
您的困惑可能源于 i
字段的定义方式 - 它看起来一旦它被设置为 0
“存在”。实际上,对零的赋值是构造函数的第一行之一(不过,重要的是,在 调用 super()
之后,构造函数通常要求这样做) .
换句话说,您的类(class)完全等同于以下内容:
public class B extends A {
private int i;
public B () {
super();
i = 0;
System.out.println(i);
}
public void init () {
i = 1;
}
}
我想您现在可以明白为什么输出是 0
而不是 1
- 因为对 init()
的调用发生在 在 字段初始化为0
之前。
出于这个原因和其他原因,总体而言,您应该避免从父类(super class)构造函数调用子类方法 - 因为此时子类甚至还没有初始化,因此很容易违反不变量。 (在未构造的对象上调用方法始终是一个非常糟糕的主意!)这是问题的根本原因,也是您应该寻求解决方案的方向。
出于这个原因,构造函数应该限制自己只调用私有(private)或最终的方法。有关详细信息,请参阅(除其他外):
关于java - 反射不返回正确的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6744567/