当我使用 this
关键字访问类中的非静态变量时,Java 不会给出任何错误。但是当我不使用它时,Java 会报错。为什么我必须使用 this
?
我知道我应该什么时候正常使用this
,但是这个例子与正常用法有很大不同。
例子:
class Foo {
// int a = b; // gives error. why ?
int a = this.b; // no error. why ?
int b;
int c = b;
int var1 = this.var2; // very interesting
int var2 = this.var1; // very interesting
}
最佳答案
完整的描述在 section 8.3.3 of the Java Language Specification: "Forward References During Field Initialization"
前向引用(指的是此时尚未声明的变量)只有在以下全部为真时才会出错:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
见粗体字:“用途是一个简单的名字”。简单名称是没有进一步限定的变量名称。在您的代码中,b
是一个简单的名称,但 this.b
不是。
但是为什么呢?
原因是,正如 JLS 示例中的草书所述:
"The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations. "
换句话说,他们允许 this.b
是因为他们认为合格的引用使您更有可能仔细考虑自己在做什么,而只是使用 b
可能意味着你犯了一个错误。
这就是 Java 语言设计者的基本原理。这在实践中是否属实,据我所知,从未被研究过。
初始化顺序
为了扩展上述内容,引用 Dukeling 对问题的评论,使用合格的引用 this.b
可能不会给你想要的结果。
我将这个讨论限制在实例变量上,因为 OP 只提到了它们。 JLS 12.5 Creation of New Class Instances 中描述了实例变量的分配顺序。 . 您需要考虑到首先调用父类(super class)构造函数,并且初始化代码(赋值和初始化 block )按文本顺序执行。
所以给定
int a = this.b;
int b = 2;
你最终会得到 a
为零(在 a
的初始化程序执行时 b
的值)并且 b
为 2.
如果父类(super class)构造函数调用一个在子类中被覆盖的方法,并且该方法为 b
赋值,则可以实现更奇怪的结果。
因此,一般来说,最好相信编译器并重新排序字段或在循环初始化的情况下修复潜在问题。
如果您需要使用 this.b
来解决编译器错误,那么您编写的代码可能很难被您之后的人维护。
关于java - 为什么我必须使用 "this"关键字进行前向引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46967759/