为什么我必须使用“this”关键字作为前向引用?

当我使用this关键字来访问一个类中的非静态variables时,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 } 

variables先声明然后赋值。 那个class级和这个一样:

 class Foo { int a; int b; int c = b; int var1; int var2; public Foo() { a = b; var1 = var2; var2 = var1; } } 

你不能这样做int a = b; 是因为b在创build对象时尚未定义,但是对象本身(即this )与其所有成员variables一起存在。

以下是对每一个的描述:

  int a = b; // Error: b has not been defined yet int a = this.b; // No error: 'this' has been defined ('this' is always defined in a class) int b; int c = b; // No error: b has been defined on the line before 

Java语言规范第8.3.3节“ 字段初始化期间的前向引用

前向引用(指的是那个时候还没有声明的variables)只有在以下情况下才是错误的:

  • 在实例variables的使用之后,类或接口C中的实例variables的声明以文本forms出现;

  • 在C的实例variables初始值设定项或C的实例初始值设定项中,使用是简单的名称 ;

  • 使用不在作业的左侧;

  • C是封闭使用的最内层的类或接口。

看到粗体文本:“使用是一个简单的名字”。 简单的名字是一个没有进一步资格的variables名称。 在你的代码中, b是一个简单的名字,但是this.b不是。

但为什么?

原因是,正如JLS例子中的草书所述:

“上面的限制旨在在编译时捕获循环或其他格式不正确的初始化。”

换句话说,他们允许this.b是因为他们认为合格的参考使得你更仔细地思考过你在做什么,而仅仅使用b可能意味着你犯了一个错误。

这是Java语言的devise者的基本原理。 据我所知,在实践中这是否属实,从未被研究过。

初始化顺序

为了扩大上述内容,参考杜克林对这个问题的评论,使用一个合格的参考文献this.b将可能不会给你你想要的结果。

我限制这个讨论的实例variables,因为OP只提到他们。 JLS 12.5创build新类实例中描述了实例variables分配的顺序。 您需要考虑到首先调用超类构造函数,并且初始化代码(分配和初始化块)按文本顺序执行。

如此给予

 int a = this.b; int b = 2; 

你将以0为零(执行初始化程序时的b值)和b为2。

如果超类的构造函数调用在子类中重写的方法,并且该方法为b赋值,则甚至可以实现更奇怪的结果。

所以,一般来说,相信编译器是一个好主意,要么重新sorting你的字段,要么在循环初始化的时候解决底层的问题。

如果您需要使用this.b来解决编译器错误,那么您可能编写的代码将很难由后面的人维护。

你已经提出了三种情况:

  1. int a = b; int b;
    这会产生错误,因为编译器会在内存中查找b ,并且它不会在那里。 但是当你使用this关键字时,它明确地指定了b在类的范围内被定义,所有的类的引用将被查找,最后它会find它。
  2. 第二种情况非常简单,正如我所描述的, b是在c之前的范围内定义的,并且在内存中查找b时不会成为问题。
  3. int var1 = this.var2;
    int var2 = this.var1;
    在这种情况下,没有错误,因为在每种情况下,variables都是在类中定义的,赋值使用它将在类中寻找指定的variables,而不仅仅是后面的上下文。

对于Java中的任何类, this是一个默认的引用variables(当没有给出具体的引用时),用户可以给出或编译器将在非静态块内提供。 例如

 public class ThisKeywordForwardReference { public ThisKeywordForwardReference() { super(); System.out.println(b); } int a; int b; public ThisKeywordForwardReference(int a, int b) { super(); this.a = a; this.b = b; } } 

你说int a = b; // gives error. why ? int a = b; // gives error. why ? 给出了编译时错误,因为b是在Java中Illegal Forward Reference之后声明a ,并被认为是编译时错误。

但在methods的情况下, Forward Reference变得合法

 int a = test(); int b; int test() { return 0; } 

但是在我的代码中,带有参数的构造函数在ab之前声明,但是没有给出任何编译时错误,因为System.out.println(b); 将被System.out.println(this.b);所取代System.out.println(this.b); 由编译器。

关键字this仅仅意味着当前的类的引用或者方法,构造函数或者属性被访问的引用。

 A a1 = new A(); // Here this is nothing but a1 a1.test(); // Here this is again a1 

当我们说a = this.b; 它指定b是当前的类属性,但是当我们说a = b; 因为它不在非静态块内, this不会出现,并且会查找先前声明的不存在的属性。

请查看Java语言规范: https : //docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3

这是IMO的原因: The usage is via a simple name.

所以在这种情况下,你必须使用this指定名称。