我写了这段代码,似乎编译器允许在使用'这个'访问时访问未初始化的空白最终字段。关键字:
public class TestClass
{
public final int value1;
public int value2;
TestClass(int value) {
value2 = 2 + this.value1; // access final field using 'this' before initialization gives no compiler error
//value2 = 2 + value1; // uncomment it gives compile time error - variable value1 might not have been initialized
value1 = value;
}
public static void main(String args[]) {
TestClass tc = new TestClass(10);
System.out.println("\nTestClass Values : value1 = " + tc.value1 + " , value2 = " + tc.value2);
}
}
我尝试在1.5,1.6和&amp ;;上编译它。 1.7并且在所有这三个中得到了相同的结果。
对我来说,它看起来像编译器错误,因为编译器必须在这种情况下抛出错误,但是使用'这个'关键字它不会因此而产生编码错误的范围,因为它不会被程序员忽视,因为不会抛出编译时或运行时错误。
为什么不是重复 的少数几点
- 所有答案都解释了它是如何工作的以及JLS所说的,很好,但我的真正意图应该放在第一位吗?
- 我的问题更多来自程序员的观点,而不是语言语义
答案 0 :(得分:1)
在Java中,默认值为0,所以即使你没有初始化它,编译器仍然将0指定为值。
声明但未初始化的字段将由编译器设置为合理的默认值。一般来说,此默认值为零或null,具体取决于数据类型。
来源:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
请注意,这不适用于局部变量,只有字段变量具有默认值。
答案 1 :(得分:1)
这不是错误。这是Java Specification 1.6及更低版本的一个特性。
可以在代码的任何部分访问最终字段。它没有任何限制。
最终的唯一限制是必须在创建类实例之前初始化它。
使用this
时,表示它是正在构造的对象的元素。
由于规范1.7 because of change,我们可能会说这是编译器的某些实现中的错误。
但是从1.8开始,代码会为this.value1
或value1
生成相同的错误。
答案 2 :(得分:0)
我使用了以下代码
public class HelloWorld {
public final int value1;
public int value2;
public HelloWorld(int value){
System.out.println(this.value1);
System.out.println(this.value2);
value1 = value;
}
public static void main(String args[]) {
}
}
它生成的字节码是
Compiled from "HelloWorld.java"
public class test.HelloWorld extends java.lang.Object{
public final int value1;
public int value2;
public test.HelloWorld(int);
Code:
0: aload_0
1: invokespecial #11; //Method java/lang/Object."<init>":()V
4: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_0
8: getfield #20; //Field value1:I
11: invokevirtual #22; //Method java/io/PrintStream.println:(I)V
14: aload_0
15: iload_1
16: putfield #20; //Field value1:I
19: return
public static void main(java.lang.String[]);
Code:
0: return
}
如果您注意到JVM在最终的情况下进行getstatic
调用,在正常实例变量的情况下进行getfield
。现在,如果你看一下它所说的specs for getstatic
成功解析字段后,如果尚未初始化该类或接口,则初始化声明已解析字段的类或接口(第5.5节)。
因此,如果您将此函数与最终变量一起使用,则将其初始化。不是它会初始化this.value1
而不是value1
这是最终的。在使用之前,您仍需要对其进行初始化。