1.内部类引用外部类局部变量时,外部类的局部变量一定要用final修饰。
因为内部类和外部类的局部变量生命周期不一样,外部类方法执行完该局部变量可能会被释放掉,但该方法中的内部类可能还在执行(如线程),还要使用该变量,所以外部类变量设置为final的,变成常量,使用的时候内部类可以复制一个副本过去,相当于就不使用该局部变量了。
我们还可以从JVM的角度去解释这个现象,在编译期的时候,所有的类都会被编译成Class文件。内部类也会被编译成Class文件。但是上面的例子的内部类编译会和我们所知道的普通类编译方式会有些不同。
大多数的类在编译的时候,需要知道每个方法需要为其所有的局部变量分配多少内存。所以它会去检查方法内定义的变量,从而确定此方法到真正运行的时候需要在栈中开辟多少内存。但这只是计算需要多少内存,真正分配内存是在运行期。
所以当内部类使用外部类的局部变量时,在编译期也会给它分配额外的内存,并给它赋与外部类相等的值,但是此变量已经不是外部的局部变量了。在内存的角度上看,匿名内部类的i实际上不是外部的i,它们使用的内存空间都不同,只是它们的值相同。
其实本质上来说,完全可以当作两个不同的变量去使用,但是Java的设计人员可能想要保持一致性,因为Java的初学者在不了解其中真正的机制的时候,会以为他们就是同一个变量,所以干脆就把变量强制定义为final,这样变量就不能被重新赋值,营造一种他们是同一个变量的“假象”。
2.内部类引用外部类的成员变量时,成员变量不一定要用final修饰,因为它不需要像上面说的那样要需在栈中重新开辟一个空间,而是内部类持有外部类的引用,可以使用外部类类名.this.变量名的方式。