原理分析:
图片摘自网络,未找到原作者,如需删除请告知
为什么内部类可以直接访问外部类的成员,而外部类不能直接访问内部类?
首先写一个类:
编译之后产生两个文件:
用javap反编译Outter$Inner.class:
答:可以看到,内部类中保存的有外部类的引用,所以内部类可以直接访问外部类的成员。通过同样的方式反编译Outter.class文件后会发现外部类中没有传入内部类的引用。
为什么局部内部类和匿名内部类只能访问被final修饰的局部成员?
注:JDK1.8之后虽然不写final编译器并不会报错,但是依然不允许修改被使用的局部成员,相当于隐式的添加了final修饰词。
这是一个编译器设计的问题,从代码中直接看,很容易让人误解为内部类直接使用了局部成员(参数)。实际上并不是这样的。
1 | public class Outter { |
可以这么理解:局部有个变量name,当内部类要使用的时候就会使“内部类name”=“局部变量name”,然后去使用这个“内部类name”。这么做很容易出现问题,如果这个“内部类name”改变了,“局部变量name”是不会随着改变的。为了解决这个问题,编译器要求这个被使用的“局部变量name”被final修饰。(被访问的外部类成员不需要final修饰,因为内部类中有外部类的引用,所有的变量修改都会真实的反映到内部类和外部类中)
反编译之后,会发现实际上的操作是这样的:
在show()方法之前增加了一个初始化的操作,可以这么理解:
1 | public class Outter { |
答:
- 保证一致性:在内部类中通过构造器将局部的变量copy了一份,然后使用copy后的变量。实际上内部类中使用的是自身的属性。所以为了保持“本体”和“克隆体”的一致性,必须加上final修饰符。
- 改变变量的生命周期:当局部方法结束时,局部变量的生命周期就结束了,但是局部内部类(匿名内部类)对象的生命周期可能还没有结束,这时对象再去使用局部变量就变得不可能了,给局部变量加上final修饰符其实就是改变了它的生命周期。