我会尝试在编译器层进行解释。
假设你有这样的方法:
int x;
x = 1;
System.out.println(x);
编译会成功,执行也会成功。
如果将方法更改为:
System.out.println(x);
int x;
x = 1;
它甚至不会像您给定的示例那样进行编译。
编译器复制代码{ }
初始化程序进入ctor
还有x=1
初始化。
正如你所说,如果你设置了它就会起作用x=1
之前{ }
初始化程序。
public class MainC {
public static void main(String args[]) {
new MainC();
}
int x=1;
{
System.out.println(x);
}
}
请参阅以下 Java 字节码:
public MainC();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field x:I
9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_0
13: getfield #2 // Field x:I
16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
19: return
LineNumberTable:
line 1: 0
line 7: 4
line 9: 9
line 10: 19
场x
被声明并获取值1
在使用它之前System.out.println
call.
那么为什么如果你在之后设置它就不起作用{ }
出于同样的原因
你不能使用我的第二个例子的代码。该字段是在使用之后声明的,这是没有意义的。
那么为什么它与this
关键词?!
让我们看一些代码:
public class Main {
public static void main(String args[]) {
new Main();
}
{ System.out.println(this.x); } //Error here
int x=1;
}
该ctor对应的Java字节码:
public Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_0
8: getfield #3 // Field x:I
11: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
14: aload_0
15: iconst_1
16: putfield #3 // Field x:I
19: return
LineNumberTable:
line 1: 0
line 7: 4
line 9: 14
那么这里发生了什么?简单讲一下this
关键字加载 Main 对象
堆栈上的引用。之后可以访问字段 x,以便System.out.println
调用即可成功执行。