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)的封闭块的局部变量和参数。
譬如,以下代码从 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("方法二");}
}
最后,我们可以总结出几下点:
本文发布于:2024-01-29 07:16:08,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648377513613.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |