1.前言
本文的前提基于jdk8以前,在jdk1.8之后,匿名内部类使用局部变量的时候,局部变量已经不需要使用final修饰了,可以编译通过。(前提是内外类都不对变量进行修改)
2.一些常识
(1)Java中数据类型分为两大类:基本数据类型和引用数据类型。相应的,变量也分为基本类型和引用类型。基本类型的变量保存原始值,即它代表的值就是数值本身,而引用类型的变量保存引用值,"引用值"指向内存空间的地址,也就是地址值,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置
(2)final修饰的变量,赋予过初值之后,不允许变更。对基本类型而言,其保存的原始值不能变更,对引用类型而言,其引用的地址值不允许变更,也就是说不能引用其他对象
3.解释一
匿名内部类使用了局部变量,那么编译器会将使用的值拷贝一份,作为构造函数的一个参数传递进来(构造函数是编译器自动添加)。因为局部变量在方法或者代码块执行完毕,就会被销毁,所以编译器在编译的时候,就拷贝了一份局部变量存储的字面值或者地址值,这样局部变量被销毁时,匿名内部类依然拥有之前传递进来的值。
假如传递到匿名内部类的局部变量,不加final修饰,那么意味着局部变量可以改变,这就意味着匿名内部类里面值的变更和外部的变量的变更不能同步,虽然内部类持有的是局部变量值的拷贝,但是语义应该保持一致,语义保持一致的前提是值要能同步,因为java编译器的设计无法提供两边同步变更的机制,所以直接锁死,不允许内外变更.
4.解释二
内部类的方法和外部类的变量生命周期是不一样的
局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法出栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失,当局部类的方法想用这个局部变量,就无法调用了。
因此:如果用final修饰会在类加载的时候进入常量池,外部方法出栈,常量池的常量还在,也可以继续使用。