我的理解是你不能在声明它之前引用变量,并且所有代码(包括实例初始值设定项)都在一个类的主体内,但在任何方法之外,在构造函数之前按顺序执行创建对象(例外是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
}
}
答案 0 :(得分:4)
来自docs:
Java编译器将初始化程序块复制到每个构造函数中。 因此,这种方法可用于共享一段代码 多个构造函数。
以上陈述略有误导,因为如果我们按照上述文档的说明,我们可以像这样重写原始代码:
public class WrongVersionOfWhyIsThisOk {
int a = 10;
public WhyIsThisOk (){
a = 5;
}
public static void main(String[] args){
WrongVersionOfWhyIsThisOk why = new WrongVersionOfWhyIsThisOk ();
System.out.println(why.a);
}
}
但是运行WrongVersionOfWhyIsThisOk
将产生原始代码产生的5而不是10。
但实际上,初始化程序块和变量赋值都被复制到构造函数中:
public class RightVersionOfWhyIsThisOk {
int a;
public RightVersionOfWhyIsThisOk (){
a = 5;
a = 10;
}
public static void main(String[] args){
RightVersionOfWhyIsThisOk why = new RightVersionOfWhyIsThisOk ();
System.out.println(why.a);
}
}
<强>更新强>
这是doc详细描述初始化顺序和构造函数调用:
4)执行实例初始值设定项和实例变量 此类的初始值设定项,分配实例变量的值 初始化器到相应的实例变量中 从左到右的顺序,它们在源代码中以文本形式出现 为了上课。如果执行任何这些初始化程序导致 异常,然后没有处理进一步的初始化程序 程序突然完成同样的异常。除此以外, 继续第5步。
5)执行此构造函数的其余部分。如果执行 突然完成,然后这个程序突然完成 同样的道理。否则,此过程正常完成。
答案 1 :(得分:1)
在实例创建时调用实例初始化块。所以在创建为什么对象之后,它是正常的,这是正常的。
初始化的顺序是: 1)静态集团 2)构造 3)出现顺序的实例集团
答案 2 :(得分:1)
只要调用任何构造函数(在构造函数的内容之前),就会执行初始化程序块的内容。
因此,您可以提供对任何变量的引用,因为除非调用构造函数,否则它们将不会被使用。对象已创建。
答案 3 :(得分:1)
来自docs:
8.3.2.3。初始化期间使用字段的限制
成员的声明需要以文本形式出现 仅当成员是实例(分别是静态)字段时才使用 类或接口C以及以下所有条件:
用法发生在C的实例(分别是静态)变量初始化器或实例(分别是静态)初始化器中 C。
用法不在作业的左侧。
用法是通过一个简单的名称。
C是封闭用法的最里面的类或接口。
如果上述四个要求中的任何一个是,则是编译时错误 不符合
在这种情况下,用法位于赋值的左侧,因此它不是编译时错误。
答案 4 :(得分:0)
声明的顺序并不重要。你也可以写:
public class WhyIsThisOk {
{
a = 5;
}
public WhyIsThisOk() {
}
public static void main(String[] args) {
System.out.println(new WhyIsThisOk().a);
}
int a = 10;
}
重要的是,编译器首先将a=5
然后a=10
复制(自上而下)到构造函数中,所以它看起来像:
public WhyIsThisOk() {
a = 5;
a = 10;
}
最后看一下这个例子:
public class WhyIsThisOk {
{
a = get5();
}
public WhyIsThisOk() {
a = get7();
}
public static void main(String[] args) {
System.out.println(new WhyIsThisOk().a);
}
int a = get10();
public static int get5() {
System.out.println("get5 from: " + new Exception().getStackTrace()[1].getMethodName());
return 5;
}
public static int get7() {
System.out.println("get7 from: " + new Exception().getStackTrace()[1].getMethodName());
return 7;
}
public static int get10() {
System.out.println("get10 from: " + new Exception().getStackTrace()[1].getMethodName());
return 10;
}
}
输出是:
get5 from: <init>
get10 from: <init>
get7 from: <init>
7