1. 概述
- Lambda表达式中,this在词法上绑定到周围的类 (定义该Lambda表达式时所处的类)
- 匿名类中,this在词法上绑定到匿名类
- 匿名类中,如果需要引用周围类的this,需要使用qualified this
由于Lambda表达式和匿名类中this引用不相同的对象问题,引入qualified this,即如何让this引用相同对象。
2. 演示
我们将演示Lambda表达式和匿名表达式中的this用法,二者稍有不同。
首先看看采用Lambda表达式的示例:
public class ThisPointer {
public static void main(String[] args) {
ThisPointer thisPointer = new ThisPointer("manerfan");
new Thread(thisPointer.getPrinter()).start();
}
private String name;
@Getter
private Runnable printer;
public ThisPointer(String name) {
this.name = name;
//使用Lambda表达式定义了printer属性,并且含有this语法
this.printer = () -> System.out.println(this);
}
@Override
public String toString() {
return "hello " + name;
}
}
在ThisPointer类的构造函数中,使用Lambda表达式定义了printer属性,并重写了类的toString方法
运行后结果:
hello manerfan //说明this指代外部类ThisPointer
下面我们来改造一下,然后对比下结果,在ThisPointer类的构造函数中,将printer属性的定义改为匿名类,而不是Lambda表达式:
public class ThisPointer {
public static void main(String[] args) {
ThisPointer thisPointer = new ThisPointer("manerfan");
new Thread(thisPointer.getPrinter()).start();
}
private String name;
@Getter
private Runnable printer;
public ThisPointer(String name) {
this.name = name;
//修改了这里,改为匿名表达式
this.printer = new Runnable() {
@Override
public void run() {
System.out.println(this);
}
};
}
@Override
public String toString() {
return "hello " + name;
}
}
重新运行后结果:
ThisPointer$1@782b1823 //结果和Lambda表达式不同,此处是匿名内部类ThisPointer$1,别说不知道$1是什么意思啊,那是内部类的
是不是很奇怪,Lambda表达式的作用类似匿名表达式,但是结果却不一样,说明不能直接划等号。
可见,Lambda表达式及匿名类中的this指向的并不是同一内存地址。这里我们需要理解,在Lambda表达式中它在词法上绑定到周围的类 (定义该Lambda表达式时所处的类),而在匿名类中它在词法上绑定到匿名类
简单来说Lambda表达式内的this指创建Lambda表达式的紧邻的外部类,而匿名表达式内的this指 匿名表达式自身
2.1 如何让匿名表达式中的this指代外部类
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.
那,如何在匿名类中如何做到Lambda表达式的效果,获取到周围类的this呢?这时候就必须使用qualified this了,如下:
public class ThisPointer {
public static void main(String[] args) {
ThisPointer thisPointer = new ThisPointer("manerfan");
new Thread(thisPointer.getPrinter()).start();
}
private String name;
@Getter
private Runnable printer;
public ThisPointer(String name) {
this.name = name;
this.printer = new Runnable() {
@Override
public void run() {
//修改此处代码,此时,使用外部.this语法,表示引用外部类实例
System.out.println(ThisPointer.this);
}
};
}
@Override
public String toString() {
return "hello " + name;
}
}
运行结果如下:
hello manerfan //成功了,达成预期
3. 小结
Lambda表达式中,this在词法上绑定到周围的类 (定义该Lambda表达式时所处的类)
匿名类中,this在词法上绑定到匿名类
匿名类中,如果需要引用周围类的this,需要使用qualified this