Lui*_*ese 25 java initialization
试图编译这段代码
public class Main {
public static void main(String args[]) {
new Main();
}
{ System.out.println(x); } //Error here
int x=1;
}
Run Code Online (Sandbox Code Playgroud)
产生cannot reference a field before it is defined错误.但是如果我将初始化器行更改为
{ System.out.println(this.x); }
Run Code Online (Sandbox Code Playgroud)
它就像一个魅力,打印默认的int值0.
这对我来说有点混乱,为什么会this有所不同呢?在这种情况下,它不应该是多余的吗?任何人都可以解释我幕后发生的事情,以明确它是如何工作的吗?
PS:我知道通过x在初始化程序之前声明它也可以使它工作.
Zel*_*don 11
我将尝试在编译器层上进行解释.
假设你有一个方法:
int x;
x = 1;
System.out.println(x);
Run Code Online (Sandbox Code Playgroud)
编译将成功并执行.如果您将方法更改为:
System.out.println(x);
int x;
x = 1;
Run Code Online (Sandbox Code Playgroud)
它甚至不会与您给出的示例编译相同.
编译器复制的代码{ }初始化器进入
ctor,也是x=1初始化.
正如你所说,如果你x=1在{ }初始化器之前设置它就有效.
public class MainC {
public static void main(String args[]) {
new MainC();
}
int x=1;
{
System.out.println(x);
}
}
Run Code Online (Sandbox Code Playgroud)
请参阅以下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
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
所以这里发生了什么?轻松说出this关键字加载堆栈上的主对象引用.之后,可以访问字段x,以便System.out.println可以成功执行调用.
JSL 8.6应解释您的编译时错误:
允许实例初始值设定项通过关键字this(§15.8.3)引用当前对象...
使用在使用后以声明方式显示声明的实例变量有时会受到限制,即使这些实例变量在范围内也是如此.有关控制实例变量的前向引用的精确规则,请参见§8.3.3.
在§8.3.3中,它说:
使用在使用后以声明方式显示声明的实例变量有时会受到限制,即使这些实例变量在范围内也是如此.具体来说,如果满足以下所有条件,则为编译时错误:
在使用实例变量之后,类或接口C中的实例变量的声明以文本形式出现;
在C的实例变量初始值设定项或C的实例初始值设定项中使用是一个简单的名称 ;
使用不在作业的左侧;
C是封闭使用的最内层类或接口.
这就是为什么写简单名称x会给你带来错误.