来自JLS
的众所周知的example关于incorrect forward reference
错误:
class Test1 {
int i = j; // compile-time error:
// incorrect forward reference
int j = 1;
}
好的,我说,并使用关键字this
:
class Test1 {
int i = ++this.j;
{
// line#4: System.out.println("j = " + j); // compile-time error: illegal forward reference
System.out.println("j = " + this.j);
}
int j = this.j + 1;
{
System.out.println("j = " + j);
}
}
输出将是:
j = 1
j = 2
谁可以解释为什么我无法访问第4行中的变量j
?
是否在此行中初始化变量j
?
如果不是,我如何在下一步1
和this.j
获得价值2
?
如果是,为什么我无法通过simple name
访问?
答案 0 :(得分:1)
看起来正在发生的事情类似于this question中发生的事情。 如果您设法解决语言限制并引用未初始化的变量,它将具有默认值(在int的情况下为0)。
所以在这种情况下,你打电话给int i = ++this.j
。由于尚未初始化,因此它取值0,然后递增。在您的下一个电话中,它会保留之前的值,并为其添加一个值。
我发现another answer更详细地介绍了初始化的限制。关键部分是这个
成员的声明需要以文本形式出现 仅当成员是实例(分别是静态)字段时才使用 一个类或接口C和所有以下条件保持
...
- 用法是通过简单的名称
所以基本上,你所做的只是因为语言设计师并没有明确禁止它。
要处理问题的其他部分,我会引用Java documentation。
Java编译器将初始化程序块复制到每个构造函数中。
所以你编写的初始化代码发生在对象的构造函数中。创建对象时,将使用值0初始化两个变量,然后运行代码以修改这些值。所以不行,int i = ++this.j;
行没有初始化j
。这会在到达该行之前自动发生。
答案 1 :(得分:0)
问:是否在此行中初始化变量j?**
是的,它已初始化,如下面的java代码类文件中所示。
// Compiled from Test1.java (version 1.6 : 50.0, super bit)
public class com.test.java.Test1 {
// Field descriptor #6 I
int i;
// Field descriptor #6 I
int j;
// Method descriptor #9 ()V
// Stack: 4, Locals: 1
public Test1();
0 aload_0 [this]
1 invokespecial java.lang.Object() [11]
4 aload_0 [this]
5 aload_0 [this]
6 dup
7 getfield com.test.java.Test1.j : int [13]
10 iconst_1
11 iadd
12 dup_x1
13 putfield com.test.java.Test1.j : int [13]
16 putfield com.test.java.Test1.i : int [15]
19 aload_0 [this]
20 aload_0 [this]
21 getfield com.test.java.Test1.j : int [13]
24 iconst_1
25 iadd
26 putfield com.test.java.Test1.j : int [13]
29 return
Line numbers:
[pc: 0, line: 4]
[pc: 4, line: 5]
[pc: 19, line: 10]
[pc: 29, line: 4]
Local variable table:
[pc: 0, pc: 30] local: this index: 0 type: com.test.java.Test1
}
关于为什么你不能用简单名称访问j的问题,它可能与编译器如何智能地重新组织并用this.j替代对j的直接访问有关。这看起来当你尝试在初始化块中访问它时不会发生(我不知道的原因),但下面的代码使用直接引用(可能是因为编译器在我们尝试访问j时巧妙地放置了这个引用)
public Test1() {
System.out.println(j);
}
int i = ++this.j;
{
// line#4: System.out.println("j = " + j); // compile-time error: illegal forward reference
//System.out.println("j = " + this.j);
}
int j = this.j + 1;