Java 变量捕获(Captured Variable)

阅读: 评论:0

Java 变量捕获(Captured Variable)

Java 变量捕获(Captured Variable)

Java 变量捕获(Captured Variable)

  • 引言
  • 什么是变量捕获
  • 总结

引言

Java 中的局部类(Local Class,本地类)和匿名类(Anonymous Class)都存在变量捕获(captured variable)。

只有理解了什么是变量捕获之后,我们后续才能更好地理解 Lambda 表达式的作用域,因为 Lambda 表达式也存在变量捕获。

什么是变量捕获

首先,我们知道局部类和匿名类都可以访问封闭类的成员,例如以下代码:

package st;public class ScopeTest {interface Say {public void say();}private String member = "我是封闭类的成员";public void print() {class LocalClass {public void say() {// 局部类可以访问封闭类的成员System.out.println(member);}}LocalClass localClass = new LocalClass();localClass.say();}public void print2() {Say say = new Say() {@Overridepublic void say() {// 匿名类可以访问封闭类的成员System.out.println(member);}};say.say();}public static void main(String[] args) {ScopeTest test = new ScopeTest();test.print();test.print2();}
}

此外,局部类和匿名类也都可以访问局部变量(本地变量)。但是,它们只能访问由 final 声明的局部变量。当局部类或匿名类访问封闭块的局部变量或参数时,还会捕获该局部变量或参数。譬如以下代码:

package st;public class ScopeTest {interface Say {public void say();}private String member = "我是封闭类的成员";public void print(final String param) {final String local = "我是局部变量";class LocalClass {public void say() {// 局部类可以访问封闭类的成员System.out.println(member);// 局部类可以访问封闭块的最终局部变量和参数// 从 Java 8 开始,在方法中声明的局部类可以访问方法的参数System.out.println(param + "t" + local);}}LocalClass localClass = new LocalClass();localClass.say();}public void print2(final String param) {final String local = "我是局部变量";Say say = new Say() {@Overridepublic void say() {// 匿名类可以访问封闭类的成员System.out.println(member);// 匿名类可以访问封闭块的最终局部变量和参数// 从 Java 8 开始,在方法中声明的匿名类可以访问方法的参数System.out.println(param + "t" + local);}};say.say();}public static void main(String[] args) {ScopeTest test = new ScopeTest();test.print("方法一");test.print2("方法二");}
}

上面代码中的变量 local 我们就称之为捕获的变量(captured variable)

注意,从 Java 8 开始,局部类和匿名类都可以访问最终(final)实际上的最终(effectively final)的封闭块的局部变量和参数。

实际上的最终(effectively final)
在初始化之后其值永远不会改变的变量或参数。

譬如,以下代码从 Java 8 开始都是有效的:

package st;public class ScopeTest {interface Say {public void say();}private String member = "我是封闭类的成员";public void print(String param) {// 从 Java 8 开始有效String local = "我是局部变量";class LocalClass {public void say() {// 局部类可以访问封闭类的成员System.out.println(member);// 局部类可以访问封闭块的实际上的最终局部变量和参数// 从 Java 8 开始,在方法中声明的局部类可以访问方法的参数System.out.println(param + "t" + local);}}LocalClass localClass = new LocalClass();localClass.say();}public void print2(String param) {// 从 Java 8 开始有效String local = "我是局部变量";Say say = new Say() {@Overridepublic void say() {// 匿名类可以访问封闭类的成员System.out.println(member);// 匿名类可以访问封闭块的实际上的最终局部变量和参数// 从 Java 8 开始,在方法中声明的匿名类可以访问方法的参数System.out.println(param + "t" + local);}};say.say();}public static void main(String[] args) {ScopeTest test = new ScopeTest();test.print("方法一");test.print2("方法二");}
}

但是,当我们使用赋值语句改变了实际上的最终变量时,编译器就会报错。譬如以下代码在编译时就会报错:

package st;public class ScopeTest {interface Say {public void say();}private String member = "我是封闭类的成员";public void print(String param) {// 从 Java 8 开始有效String local = "我是局部变量";class LocalClass {public void say() {// 局部类可以访问封闭类的成员System.out.println(member);// 编译器报错:Variable 'param' is accessed// from within inner class, needs to be final or effectively finalparam = "改变";// 编译器报错:Variable 'local' is accessed// from within inner class, needs to be final or effectively finallocal = "改变";// 局部类可以访问封闭块的实际上的最终局部变量和参数// 从 Java 8 开始,在方法中声明的局部类可以访问方法的参数System.out.println(param + "t" + local);}}LocalClass localClass = new LocalClass();localClass.say();}public void print2(String param) {// 从 Java 8 开始有效String local = "我是局部变量";Say say = new Say() {@Overridepublic void say() {// 匿名类可以访问封闭类的成员System.out.println(member);// 编译器报错:Variable 'param' is accessed// from within inner class, needs to be final or effectively finalparam = "改变";// 编译器报错:Variable 'local' is accessed// from within inner class, needs to be final or effectively finallocal = "改变";// 匿名类可以访问封闭块的实际上的最终局部变量和参数// 从 Java 8 开始,在方法中声明的匿名类可以访问方法的参数System.out.println(param + "t" + local);}};say.say();}public static void main(String[] args) {ScopeTest test = new ScopeTest();test.print("方法一");test.print2("方法二");}
}

总结

最后,我们可以总结出几下点:

  • 匿名类除了没有名字外,其它和局部类并没有什么不同(这不是本文的结论,这是官方的说法:“They are like local classes except that they do not have a name.”)
  • 从 Java 8 开始,局部类和匿名类都可以访问最终(final)实际上的最终(effectively final)的封闭块的局部变量和参数
  • 实际上的最终是指在初始化之后其值永远不会改变的变量或参数

本文发布于:2024-01-29 07:16:08,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170648377513613.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:变量   Java   Variable   Captured
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23