"this"在匿名类和lambda表达式中的值

Meh*_*lik 8 java lambda anonymous-class java-8

我对匿名类和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!
Run Code Online (Sandbox Code Playgroud)

使用匿名类时:

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$1@1db9742
         Package_Name.Test$2@106d69c
Run Code Online (Sandbox Code Playgroud)

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

4ca*_*tle 11

在lambda表达式中,this词法绑定到周围的类,而在匿名类this中,词法绑定到匿名类.

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

与出现在匿名类的声明,名称的含义和代码this,并super在一个lambda身体出现关键词,与引用声明的可访问性一起,是同周围环境(除了拉姆达参数引入新的名称).

thislambda表达式的主体(包括显式和隐式)的透明度- 也就是说,将其视为与周围上下文相同 - 允许实现更灵活,并防止正文中非限定名称的含义依赖于超载分辨率.

实际上,lambda表达式需要谈论自身(要么递归地调用自身还是调用其他方法)是不寻常的,而更常见的是想要使用名称来引用封闭类中的内容.否则被遮蔽(this,toString()).如果lambda表达式需要引用它自己(就像via this),则应该使用方法引用或匿名内部类.

为了this从匿名类中引用周围的类,您必须使用限定类this.

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

  • 这不仅会影响`this`和`super`.在匿名内部类中,可能存在继承的成员(不仅是`toString()`)而lambda表达式不会从功能接口继承任何内容. (3认同)
  • @MehrajMalik这意味着它们在编译时根据它们的上下文绑定. (2认同)