内部类引用外部类的局部变量要用final修饰

为什么内部类引用外部类的局部变量时,此变量要用final修饰

如图

   public void test() {
   
       final int i = 3;
       
       runOnUiThread(new Runnable() {
           @Override
           public void run() {
               mTvShow.setText(String.valueOf(i));
           }
       });
   }
  

上面的代码是使用了匿名内部类的方式。Runnable是一个接口,此内部类实现了Runnable方法,重写了接口里面的run()方法,方法内引用了外部方法体内的局部变量 i,这个时候i只能被定义为final变量,否则编译会报错。

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

为什么引用外部类的成员变量的时候,又不用final修饰呢?

有一点要注意,当引用的不是局部变量而是外部类的成员变量的时候,不一样要用final修饰,因为它不需要像上面说的那样需要在栈中重新开辟一个空间,而是内部类持有外部类的引用,可以直接引用外部类的成员变量。

与C/C++的不同

在C++中,同样的现象,引用外部类的局部变量时,是不用加final了。其根本原因是出在,C++在编译期的时候就进行动态连接了,而Java是在运行期的时候才进行动态连接。
  说白了,就是C++的编译时就已经分配好了空间,自然外部类和匿名内部类的i其实用的是同一块内存区域,是真正意义上的同个变量,所以不需要加final。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 33,799评论 18 399
  • Java 内部类 分四种:成员内部类、局部内部类、静态内部类和匿名内部类。 1、成员内部类: 即作为外部类的一个成...
    ikaroskun阅读 5,072评论 0 13
  • 这里所说的“匿名内部类”主要是指在其外部类的成员方法内定义,同时完成实例化的类,若其访问该成员方法中的局部变量,局...
    妍倩倩阅读 2,682评论 0 2
  • 落叶余晖, 可曾搁浅了忧伤, 浅浅的那份缘, 不知情结何处? 瞭望漫天晚霞, 落日最后的一丝眷恋, 终究抵不住漫漫...
    夜雨山人行阅读 1,486评论 1 0
  • 其实我一直有种感觉,当我心情不好的时候,我好像会切断与我亲密的人的情感联结,有时变的无理取闹,有时变的理智不堪。此...
    Nella阅读 1,765评论 0 0

友情链接更多精彩内容