局部内部类访问它所在方法的局部变量时,要求该局部变量必须声明为final的原因

局部内部类访问它所在方法的局部变量时,要求该局部变量必须声明为final,这是java的规则,原因是什么:

思考:局部内部类对象和局部变量的生命周期谁更长?

如果没有将变量声明为final,会发生什么,代码如下:

 1 class Outer{
 2     
 3     Object obj;
 4     public void outerMethod() {
 5         
 6         //局部变量
 7         int x = 5;
 8         //定义在方法中的内部类称为局部内部类
 9         class Inner{
10 
11             public String toString() {
12                 System.out.println(x);//访问了局部变量x
13          return null; 
14             }
15         }
16         //创建内部类实例
17         Inner in = new Inner();
18         in.toString();
19         //将内部类实例的引用赋值给obj
20         obj = in;
21     }
22 }
23 public class HelloDemo {
24     
25     public static void main(String[] argr) {
26         Outer out = new Outer();
27         out.outerMethod();
28        //out.obj.toString();
29   }
30 }

 

  如上面的第7行代码所示,变量x没有被声明为final,当执行完第27行的outMethod()方法后,outMethod()方法将出栈,出栈后outMethod()方法里面定义的所有变量(x 和 in)已死亡,(但是此时内部类的对象还活着,直到它不再被使用才会被回收,结论:此内部类对象的生命周期比局部变量的生命周期长),并且在变量 in 死亡之前,in 所代表的值赋给了成员变量obj(第20行代码),即obj 指向了内部类的对象,如果此时在28行添加一句代码: out.obj.toString(); 这句代码将会访问到局部变量 x,但是 x 早已死亡了,内部类对象无法访问到 x ,因此这是相互矛盾的。所以上面的代码并不能编译通过。(在 jdk8.0 能编译通过,那是因为新版本 jdk 检测到局部内部类访问了 x,会默认给 x 的前面加上隐式的final,如果在第8行加上一句代码:x = 4;编译器将会报错,因为被 final 修饰的变量不允许改变值)

  如果局部变量 x 被声明为 final (在第七行的int前加上final),x 就代表一个常量,第12行的代码实际上就变成了 System.out.println(5); 这时内部类相当于访问了一个数字 5,访问常量 5 是没问题的,因此局部内部类访问它所在方法的局部变量时,要求该局部变量必须声明为final。

原理:局部内部类对象的生命周期比局部变量的生命周期长

posted on 2018-05-11 22:12  老酒馆  阅读(3163)  评论(1编辑  收藏  举报

导航