Java-编译器知识:为什么匿名内部类使用的局部变量必须为final?

为什么匿名内部类使用的局部变量必须为final?

public class Demo{
	public static void main(String [] args){
		final int a = 1;
		final Integer b = 1;
		InterfaceA interfaceA = new InterfaceA(){
			public int getInt(){
				return a + 1;
			}
			public int getInteger(){
				return  b + 1;
			}
		}
		System.out.println(interfaceA.getInt());
	}
}

上面的例子里面,如果编译器允许a和b不是final,会有什么问题呢?
会在语义上令人费解!如下:

public class Demo{
	public static void main(String [] args){
		int a = 1;
		Integer b = 1;
		InterfaceA interfaceA = new InterfaceA(){
			public int getInt(){
				return a;
			}
			public int getInteger(){
				return  b;
			}
		}
		a = 2;
		System.out.println(interfaceA.getInt());
	}
}

在这个例子里面,你明明在调用interfaceA.getInt()之前,已经把a的值改为了2,但interfaceA.getInt()返回的还是1.

虽然看起来匿名内部类的方法代码跟定义内部类的方法代码在同一个作用域,但实际上并非如此。编译器实际上还是以局部内部类的方式,先定义内部类,然后调用内部类构造方法,传入需要的变量(本例子中的a、b)。也就是说,内部类里面引用的外部类局部变量,实际上是通过方法参数,以值传递/地址传递的方式传递进来的新的变量。

这样就可以理解了,因为interfaceA 里面的a变量和main方法里面的a变量,看起来是一个变量,但实际上是两个作用域的变量。为了给程序员一种把这两个当成同一种变量的使用体验,而又不会在运行时出现意料不到的错误,故而在编译时要求被匿名内部类引用的变量必须为final。

简而言之,是为了让你能够将匿名内部类方法作用域与当前方法作用域当作一个作用域,而增加的一项约定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值