反射不会返回正确的实例

Man*_*uel 3 java

我有反思的有线经验.首先是一些示例代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的代码中的某处,我使用反射api来实例化一个对象B.

Class<AbstractSection> bc = (Class<AbstractSection>) Class.forName(B);
Constructor<?> bcon = bc.getConstructor();
B b = (B) bcon.newInstance();
Run Code Online (Sandbox Code Playgroud)

我期望的是B的实例,变量i设置为值'1'.我得到的是一个B的实例,我仍然设置为'0'.通过调试器仔细观察,我发现这不完全正确:我仍然没有设置为'0'.它在init()方法中更改为"1",并在super()调用返回的那一刻设置回"0".

谁有线索?提前致谢,

曼努埃尔

PS:我知道我可以通过调用init()而不是在超类中但在继承构造函数中来解决这个问题.

And*_*yle 8

对于初学者来说,这与反射无关 - 如果你自己实例化这个类,你会得到相同的结果.

你的困惑可能不同于方式茎i字段定义-它看起来像它的设置0,只要它"存在".实际上,赋值为零是构造函数的第一行(尽管如此,关键的是,在一般的构造函数需要调用之后super()).

换句话说,您的类完全等同于以下内容:

public class B extends A {

    private int i;

    public B () {
        super();
        i = 0;
        System.out.println(i);
    }

    public void init () {
        i = 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为你现在可以看到为什么输出0不是1- 因为调用是字段初始化之前init()发生的.0


正是由于这个原因以及其他原因,总的来说你应该避免从超类构造函数中调用子类方法 - 因为子类在这一点上甚至都没有被初始化,所以很容易违反不变量.(在未构造的对象上调用方法总是一个非常糟糕的主意!)这是您的问题的根本原因,以及您应该通过修复解决的方向.

出于这个原因,构造函数应该将自己限制为仅调用私有或最终的方法.有关更多详细信息,请参阅(以及其他):