java内部类访问局部变量为什么要加final

概要

java内部类访问局部变量需要加final这是一个设计问题,并不是一个技术问题。
jdk1.8里面,对局部变量赋初值后不再修改,不需要加final。虽然看起来语法变了,实际上这是个语法糖,因为赋初值后,不再修改,符合final的特征,所以编译器不强制在定义的时候加final。

为什么需要加final

内部类的生命周期可能比局部变量长,或者说内部类的方法在执行时,已经不在创建它时的那个上下文中了。如果方法执行完,局部变量就回收,就会导致空指针问题;如果为内部类单独保存它访问的局部变量的内存,就会加大gc的复杂度。

比如下面这段代码,匿名内部类真正访问a,b两个变量时,已经不在test这个方法上下文里面了。

public class App {
	public Comparator<String> test() {
	    // jdk1.8,赋初值后不修改,可以不加final
		int a = 6;
		int b = 7;
		return new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return a-b;
			}
		};
	}
	public static void main(String[] args) {
		App app = new App();
		Comparator<String> comparator = app.test();
		System.out.println(comparator.compare("", ""));
	}
}

为了实现这个功能,有两种方案:
A.匿名类中的a,b 是test中a,b两个局部变量的副本,即copy-by-value,与函数传参一样。
这种方式,test方法中a,b修改后,不会影响到匿名类中a,b的副本;这样会导致一致性的问题,所以需要加上final,不允许修改a,b。 这样匿名类中a,b的副本与test中a,b的值是一致的,不容易产生BUG。

B.匿名类中的a,b与test中a,b两个局部变量共享同一处内存,即copy-by-reference。
这种方式,匿名类中的a,b就是test中的局部变量a,b。修改其中一处,都会反映到另外一处上面。
匿名类的生命周期可能比test方法中的局部变量长,所以test方法中的a,b的内存回收不能简单的遵从局部变量的回收(不然test方法结束后,a,b的内存被释放;在main方法中执行内部类的compare时,会导致空指针),从而导致a,b不能在栈上分配内存,这样大大增加了JVM内存结构及gcc的设计难度。

为了降低系统复杂度,JVM选择了A设计。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值