我将尝试在编译器层上进行解释。
假设你有一个这样的方法:
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
那么为什么它不起作用,如果你设置它之后,从同样的原因你不能使用我的第二个例子的代码。该字段是在用法之后声明的,这毫无意义。{ }
那么为什么它与关键字一起使用?!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
那么这里发生了什么呢?简单来说,关键字将 Main 对象引用加载到堆栈上。之后,可以访问字段 x,以便可以成功执行调用。this
System.out.println