Java中Lambda表达式访问类成员字段的原理是什么?
示例代码
public class ClickButton extends JButton { private int clicks = 0; public ClickButton() { super("0"); this.addActionListener (e -> { ++clicks ; this.setText(clicks + ""); }); } }
原理说明
1. Lambda访问私有成员clicks的底层逻辑
Java对私有成员的访问校验是类级别的,只要逻辑属于当前类的代码范畴,就有权限访问该类的所有私有成员,和逻辑写在普通方法里还是Lambda里没有关系。
这段代码里的Lambda定义在ClickButton的构造方法上下文中,没有捕获局部变量,只引用了当前ClickButton实例的引用——你写的this.setText里的this就指向当前按钮实例,++clicks本质是++this.clicks的简写。Lambda对应的执行逻辑在编译阶段就被判定属于ClickButton类的权限范围,所以直接访问私有字段完全合法。
2. 不能把Lambda看作内部类的精简形式
Lambda和匿名内部类只是表面写法相似,底层实现逻辑完全不同:
- 匿名内部类在编译阶段就会生成独立的
外部类$序号.class字节码文件。因为单独的类默认没有权限访问外部类的私有成员,编译器会自动在外部类里生成带access$前缀的合成静态方法,专门给内部类调用,间接实现私有成员访问,本质是编译器做了一层中转绕开了权限校验。 - Lambda不会在编译期生成单独的类文件。编译时只会在对应位置生成一条
invokedynamic指令,等程序实际运行到这段代码时,才会动态生成Lambda的实现类、绑定执行逻辑。这段示例里的Lambda只持有外部ClickButton实例的引用,访问私有字段时不需要额外的合成中转方法,编译阶段就已经通过了类内访问的权限校验。 - 二者在这段代码里的
this指向表现看起来一致(都指向外部类实例),但权限实现、类生成机制完全不同,不能混为一谈。
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

