【Java语法】变量捕获语法机制

Java中的局部内部类、匿名内部类和Lambda表达式都存在变量捕获机制

至于具体什么叫变量捕获,我们最后在做总结,先来探讨一下关于局部内部类使用外部类的局部变量时,为什么外部类的局部变量需要加 final 修饰?

public class Outer {
	public void outerFunc(int i){
    	class Inner{
        	public void innerFunc(){
            	System.out.println(i);
        	}
    	}
    	new Inner().innerFunc();
	}
}

以上代码在jdk1.8之前会报错,但是1.8之后不会报错。编译这个类后发现产生了两个class文件也就是说内部类和外部类各一个class文件,这样就产生了一个问题,调用内部类方法的时候如何访问外部类方法中的局部变量呢?实际上编译后的内部类的构造方法的里面,传了对应的外部类的引用和所有局部变量的形参。这时产生了一个不一致的问题,如果局部变量不设为final,那内部类构造完毕后,外部类的局部变量又改变了那怎么办?比如下列代码就改变了外部类的局部变量。 

public class Outer {
	public void outerFunc(int i){
    	class Inner{
        	public void innerFunc(){
            	System.out.println(i);
        	}
    	}
    	i = 5;
    	new Inner().innerFunc();
	}
}

这样代码时会造成外部类局部变量和内部类中对应的变量的不一致。导致第5行编译报错

注意内部类编译成class文件与 new 无关,i = 5放在 new Inner() 前后不影响不一致关系,new 在JVM运行class文件时才起效

最后说明一下 jdk1.8 和之前版本对这个规则编译的区别。在 jdk1.8 之前,如果不加 final,编译直接会报错,如果在 jdk1.8 的环境下,会发现我们最开始的 Outer.java 文件编译和运行是完全没有问题的,但是这并不能说明内部类使用的局部变量可以更改了,如果我们给局部变量再赋下值会发现编译又会出现错误。也就是说规则没有改变,只是 jdk1.8 的编译变得更加智能了而已,在局部变量没有重新赋值的情况下,它默认局部变量为 final 型,认为你只是忘记加 final 声明了而已。如果你重新给局部变量改变了值或引用,那就无法默认为 final 了,所以报错。

总结

        方法里面若有局部内部类、匿名内部类和Lambda表达式的出现,且在这三者中使用了了包含这三者的方法的局部变量时,这样的局部变量就称为捕获的变量,从Java 8开始,局部内部类、匿名内部类和Lambda表达式都可以访问最终(final)或实际最终(effectively final)的局部变量和参数。

实际最终:在初始化之后值永远不会改变的变量或参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李哞哞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值