Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 反射不会返回正确的实例_Java - Fatal编程技术网

Java 反射不会返回正确的实例

Java 反射不会返回正确的实例,java,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 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();
Class bc=(Class)Class.forName(B);
构造函数bcon=bc.getConstructor();
B=(B)bcon.newInstance();
我所期望的是B的一个实例,变量我设置为值“1”。我得到的是B的一个实例,我仍然设置为“0”。 通过使用调试器仔细查看,我发现这并不完全正确:我还没有设置为“0”。它在中更改为“1” 方法,并在super()调用返回时将其设置回“0”

有人知道线索吗?提前感谢,

曼努埃尔


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

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

您的混淆可能源于
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;
    }
}
我假设您现在可以看到为什么输出是
0
而不是
1
——因为对
init()
的调用发生在字段初始化为
0
之前


正是由于这个原因,以及其他一些原因,总体而言,您应该避免从超类构造函数调用子类方法——因为此时子类甚至还没有初始化,所以很容易违反不变量。(在未构造的对象上调用方法总是一个非常糟糕的主意!)这是问题的根本原因,也是您应该寻求解决方法的方向

因此,构造函数应该限制自己只调用私有或最终的方法。有关更多详细信息,请参见(除其他外):


如果调用构造函数而不是使用反射,则没有什么区别

声明如

private int i = 0;
在调用super之后立即成为每个声明构造函数的一部分。
因此,在赋值给
0

之前调用
init
,因为执行顺序如下:子类的构造函数调用超构造函数,该超构造函数设置i=0,子类中字段的初始化然后设置i=1,最后由子类的其余构造函数执行


这遵循一般规则:对象首先由超类初始化,然后由子类初始化。这就是为什么,如果您试图在super()的参数中调用非静态方法,您会得到一个错误“无法在调用超类型构造函数之前引用它”。如果试图修改super()中的字段,则会收到另一条错误消息。这将阻止在超级构造函数初始化子类之前初始化它。

任何非静态类属性都将在类的构造函数中设置为默认值:

boolean                          false
char                             '\u0000'
byte,short,int,long              0
float, double                    +0.0f or +0.0d
object                           null

正如其他答案所述,该方法(由编译器生成并初始化字段)是在super()之后调用的,因此如下所示:

super()
    init() // i = 1
this()
    <init> // i = 0
super()
init()//i=1
这()
//i=0
我想补充一点,您不应该在构造函数中调用可能被客户端重写的方法。这可能会导致不可预测的“fuckup”;)


更多关于有效java的详细信息,现在找不到rigth项目。

解决方案是什么?删除`=0`就足够了,还是这是隐式的?@Bart van Heukelom:对于整数字段来说,这是隐式的(尽管我不确定如果删除显式赋值,
I
是否真的会被设置为零——我不打算查找它,因为如果您遵循规则,它是不相关的)。解决方案是不从(父)构造函数调用可重写的方法。所以在这种情况下,
A
的构造函数不应该调用
init()
,而
B
的构造函数应该自己调用它。@Bart von Heukelom:回答你的问题:然后它会被设置为“1”。安德烈·道尔:谢谢你的回答。非常详细和有用!