Java 局部内部类访问局部变量为什么必须加final关键字 您所在的位置:网站首页 final在java中的使用 Java 局部内部类访问局部变量为什么必须加final关键字

Java 局部内部类访问局部变量为什么必须加final关键字

2023-07-30 07:50| 来源: 网络整理| 查看: 265

1.疑问

在Java中,局部内部类如果调用了方法中的变量,那么该变量必须申明为final类型,如果不申明,则编译就会出错。

这里的内部类指的是方法内部类或匿名内部类,不包含静态内部类和成员内部类

这里通过一个例子类分析

public class InnerClass { private int defaultAge = 5; 局部变量 age,必须添加final关键字,这里先不加 public void addAge( int age){ //局部内部类 class NewAge{ private int getAge(){ return age + defaultAge; } } NewAge newAge = new NewAge(); System.out.print(newAge.getAge()); } }

强行不加final,编译,则会报错:

Error:(16, 12) 错误: 从内部类中访问本地变量age; 需要被声明为最终类型

2.分析

1.生命周期不同: 为什么必须局部变量加final关键字呢?因为局部变量直接存储在栈中,当方法执行结束,非final的局部变量就被销毁,而局部内部类对局部变量的引用依然存在,当局部内部类要调用局部变量时,就会出错,出现非法引用。简单来说,就是非final的局部变量的生命周期比局部内部类的生命周期短,是不是直接可以拷贝变量到局部内部类?这样内部类中就可以使用而且不担心生命周期问题呢?也是不可以的,因为直接拷贝又会出现第二个问题,就是数据不同步

2.数据不同步:内部类并不是直接使用传递进来的参数,而是将传递进来的参数通过自己的构造器备份到自己内部,表面看是同一个变量,实际调用的是自己的属性而不是外部类方法的参数,如果在内部类中,修改了这些参数,并不会对外部变量产生影响,仅仅改变局部内部类中备份的参数。但是在外部调用时发现值并没有被修改,这种问题就会很尴尬,造成数据不同步。所以使用final避免数据不同步的问题

那为什么添加final修饰的局部变量,就可以被局部内部类引用呢? 若定义为final,则java编译器则会在内部类NewAge内生成一个外部变量的拷贝,而且可以既可以保证内部类可以引用外部属性,又能保证值的唯一性

也就是拷贝了一个变量的副本,提供给局部内部类,这个副本的生命周期和局部内部类一样长,并且这个副本不可以修改,保证了数据的同步

注意:在Java8 中,被局部内部类引用的局部变量,默认添加final,所以不需要添加final关键词

字节码 如果有兴趣,可以看看编译后的字节码,即.class文件

命令行有两种方式 java -c 在编译后,进入字节码存放的文件夹,例如:FileA\Hello.class,使用命令行窗口,执行命令: java -c FileA\Hello.class,即可在窗口浏览字节码文件 javap -verbose HellloWorld.class javap -verbose Hello.class ,同样可以浏览字节码文件 class InnerClass$1NewAge { //可以看到,局部内部类中的使用的age,是通过构造函数传递进来,并不是直接引用外部变量。 InnerClass$1NewAge(InnerClass var1, int var2) { this.this$0 = var1; this.val$age = var2; } private int getAge() { return this.val$age + InnerClass.access$000(this.this$0); } }

InnerClass类编译后,在文件夹会出现InnerClass.class和InnerClass$1NewAge.class,这说明外部类的方法 和内部类处于同一级。

3.结论

局部内部类引用局部变量,不添加final,会出现生命周期不同,导致非法引用问题,而且直接拷贝会出现数据不同步问题,所以使用final,保证了合法引用,而且数据不可修改



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有