匿名 class 与 lambda 表达式中 "this" 的值

Value of "this" in an anonymous class vs a lambda expression

我对匿名 class 和 lambda 表达式的不同行为有点困惑。

当我使用 lambda 表达式时:

//Test.java

Runnable r1 = () -> System.out.println(this);
Runnable r2 = () -> System.out.println(toString());

@Override
public String toString() {
    return "Hello World!";  
}

// in main method 
new Test().r1.run();
new Test().r2.run();   
Output : Hello World!
         Hello World!

使用匿名时class:

Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println(this);   
    }
};

Runnable r2 = new Runnable() {
    @Override
    public void run() {
        System.out.println(toString()); 
    }
};

@Override
public String toString() {
    return "Hello World!";  
}

// in main method 
new Test().r1.run();
new Test().r2.run();  
Output : Package_Name.Test@1db9742
         Package_Name.Test@106d69c

有人可以解释不同的行为吗?

在 lambda 表达式中,this 在词法上绑定到周围的 class,而在匿名 class 中,this 在词法上绑定到匿名 [=31] =].

Java 语言规范描述了这种行为 15.27.2:

Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.

Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this, toString()). If it is necessary for a lambda expression to refer to itself (as if via this), a method reference or an anonymous inner class should be used instead.

为了从匿名 class 中引用周围 class 的 this,您必须使用 qualified this.

Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println(Test.this); // or Test.this.toString()
    }
};