【Lambda】Lambda表达式里的“陷阱“ 匿名表达式 qualified this

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

参考:
《Lambda表达式里的"陷阱" 》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值