在Java中使用“this”

The use of “this” in Java

如果我写下面的课:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Example {

      int j;
      int k;

      public Example(int j, int k) {
           j = j;
           k = k;
      }

      public static void main(String[] args) {
           Example exm = new Example(1,2);
           System.out.println(exm.j);
           System.out.println(exm.k);
      }

}

程序会编译,但是当我运行程序时,主方法会打印出两个0。我知道为了说明我要在构造函数中初始化实例变量,我必须编写:

1
2
this.j = j;
this.k = k;

但是,如果我不写它,那么在构造函数(左边和在表达式的手写边)中评估(或考虑)哪个变量?参数是变量还是实例变量?有什么区别吗?

还有其他必须使用this的情况吗?


如果不在构造函数中写入"this.variable",并且有一个局部变量(包括函数参数)与构造函数中的字段变量同名,则将考虑该局部变量;局部变量隐藏字段(也称为类变量)。

"这"是唯一的出路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class OuterClass {
  int field;

  class InnerClass {
    int field;

    void modifyOuterClassField()
    {
      this.field = 10; // Modifies the field variable of"InnerClass"
      OuterClass.this.field = 20; // Modifies the field variable of"OuterClass",
                                  // and this weird syntax is the only way.
    }
  }
}


如果在构造函数中只说j,那么编译器会认为在这两种情况下您指的都是参数。所以

1
j = j;

只需将参数j的值赋给参数j(这是一个非常无意义但仍然有效的语句)。

因此,为了消除歧义,可以将EDOCX1 3的前缀明确为:你是指同名的成员变量。

EDOCX1 4的另一个用法是当您需要将当前对象的引用传递给某种方法时,例如:

1
someObject.addEventListener(this);

在这个例子中,你需要将当前对象作为一个整体来引用(而不仅仅是对象的一个成员)。


如果不写这个,那么就将参数赋给它自己;参数变量隐藏实例变量。


另一个有用的方法(虽然很少使用)是声明方法参数最终:

以下块将不会编译,因此会立即警告您该错误:

1
2
3
4
  public Example(final int j, final int k) {
       j = j;
       k = k;
  }


当您想要返回对象本身时,这很有用

1
return this;

这很有用,因为如果一个类具有例如method1()和method2()这样的返回值,则允许您编写如下调用

1
object.Method1().Method2()

同样,在方法内部,在调用期间将对象本身传递给另一个函数也是很有用的。


你所经历的是所谓的可变阴影。查看Java中不同类型变量的概述。

一般来说,Java编译器使用它可以找到的最接近的赋值变量。在一个方法中,它首先尝试找到一个局部变量,然后将搜索的焦点扩大到类和实例变量。

我个人发现的一个好习惯(其他人不喜欢)是在成员变量前面加上m_u,并对不改变其值的常量变量使用大写。使用变量阴影的代码非常(!)很难调试和使用。


在构造函数代码中,您将为自己分配变量。"j'是在构造函数的参数中指定的j。即使它是上面定义的类变量j,那么您仍然会说"j=j"…也就是说,J的评价在左边和右边不会有所不同。

1
2
3
4
  public Example(int j, int k) {
       this.j = j;
       this.k = k;
  }

在示例中,将参数分配给自己。

更一般地说,如果不预先为变量准备一个作用域,则假定为当前作用域——在您的情况下,它是函数。"这个.j'告诉JRE在对象范围内使用变量j——对象的成员变量。


为了用方法来回答关于这个问题的后续问题,srikanth提到的内部类仍然是使用这个方法的有效例子:(这次用方法)

1
2
3
4
5
6
7
8
9
10
public class OuterClass
{
    void f() {System.out.println("Outer f()");};
    class InnerClass {
        void f() {
            System.out.println("Inner f()");
            OuterClass.this.f();
        }
    }
}

匿名类的情况也一样:

You can refer to the outer class’s methods by:

  • MyOuterClass.this.yOuterInstanceMethod(),
  • MyOuterClass.myOuterInstanceMethod(),
  • or simply myOuterInstanceMethod() if there is no ambiguity.

正如罗伯特·格兰特所说,"这就是你如何明确地表明你所指的是成员变量而不是局部变量。"


为了避免这种情况,使用一个IDE(如Eclipse),在这种情况下它将生成警告。

另外,除非你的领域绝对不可能是最终的。有很多原因(除了这一个)这样做。


您可能想看看this/self指针强制显式的优点是什么?虽然使用EDOCX1 4Ω在Java中并不是强制性的,但我确信它将对使用Java中的EDCOX1和4的主题提供一些启发。


这并不能完全回答您的问题,但是如果您使用Eclipse,您可能会发现"赋值没有效果"设置很有用。我相信这也会出现在其他IDE中。