我的理解是,在变量被声明之前,您不能引用它,并且所有代码(包括示例初始化式),它位于类的主体内,但在任何方法之外,在创建对象时按构造函数之前的顺序执行(例外是static
变量和初始化程序块,它们在程序开始时按顺序运行,初始化整个类)。那么,为什么下面的代码会编译(并运行!):
public class WhyIsThisOk {
{ a = 5; } // why is this ok???
int a = 10;
public WhyIsThisOk() {
}
public static void main(String[] args) {
WhyIsThisOk why = new WhyIsThisOk();
System.out.println(why.a); // 10
}
}
5条答案
按热度按时间qyzbxkaa1#
从docs开始:
Java编译器将初始化块复制到每个构造函数中。因此,这种方法可以用于在多个构造函数之间共享代码块。
上面的陈述有点误导,因为如果我们按照上面文档的解释,我们可以像这样重写原始代码:
但是运行
WrongVersionOfWhyIsThisOk
将产生5而不是原始代码产生的10。但实际上,初始化块和变量赋值都被复制到构造函数中:
下面是详细描述初始化顺序和构造函数调用的文档:
4)执行此类的示例初始值设定项和示例变量初始值设定项,将示例变量初始值设定项的值按它们在类的源代码中文本显示的从左到右的顺序分配给相应的示例变量。如果执行这些初始值设定项中的任何一个导致异常,则不再处理其他初始值设定项,并且此过程以相同的异常突然完成。否则,则继续步骤5。
5)执行这个构造函数体的其余部分。如果那个执行突然结束,那么这个过程也会因为同样的原因突然结束。否则,这个过程正常完成。
bcs8qyzn2#
来自文档:
8.3.2.3.初始化期间字段使用的限制
只有当成员是类或接口C的示例(分别为静态)字段,并且满足以下所有条件时,成员的声明才需要在使用之前以文本形式出现:
C.
在本例中,用法位于赋值语句的左侧,因此这不是编译时错误。
woobm2wo3#
初始化器块的内容在任何构造函数被调用时执行(在构造函数的内容之前)。
因此,您可以提供对任何变量的引用,因为除非调用构造函数(即创建对象),否则不会使用这些变量。
lzfw57am4#
示例初始化块在示例创建时调用time.so,创建why对象后,它正常工作。
初始化的顺序为:
1.静态阻塞
1.构造器
1.示例块按出现顺序排列
2w2cym1i5#
声明的顺序并不重要,您也可以这样写:
重要的是,编译器首先复制(自上而下)
a=5
,然后将a=10
复制到构造函数中,这样看起来就像:最后看这个例子:
输出为: