【176期】面试官:你知道为什么要加 final 关键字了吗?

沙海 2021年4月14日01:01:04杂谈 Java评论27字数 2929阅读9分45秒阅读模式
摘要

速读摘要

速读摘要文章源自JAVA秀-https://www.javaxiu.com/11859.html

从表面上当然看不出什么原因,看看编译器做了什么工作吧!匿名内部类也会被当作普通的类处理,只不过编译器生成它构造方法的时候,除了将外部类的引用传递了过来,还将基本数据类型的变量复制了一份过来,并把引用数据类型的变量引用也传递了过来。基本数据类型的变量当然不能修改了,不然就会跟外部的变量产生不一致,这样的话变量的传递也就变得毫无意义了。文章源自JAVA秀-https://www.javaxiu.com/11859.html

原文约 1424 | 图片 8 | 建议阅读 3 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?

戳一戳→ 程序员的成长之路 文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

程序员的成长之路文章源自JAVA秀-https://www.javaxiu.com/11859.html

互联网/程序员/技术/资料共享 文章源自JAVA秀-https://www.javaxiu.com/11859.html

关注文章源自JAVA秀-https://www.javaxiu.com/11859.html

阅读本文大概需要 2.8 分钟。文章源自JAVA秀-https://www.javaxiu.com/11859.html

来自:www.jianshu.com/p/acc8d9a67d0c文章源自JAVA秀-https://www.javaxiu.com/11859.html

在开发过程中,由于习惯的原因,我们可能对某种编程语言的一些特性习以为常,特别是只用一种语言作为日常开发的情况。文章源自JAVA秀-https://www.javaxiu.com/11859.html

但是当你使用超过一种语言进行开发的时候就会发现,虽然都是高级语言,但是它们之间很多特性都是不太相同的。文章源自JAVA秀-https://www.javaxiu.com/11859.html

现象描述

在  Java 8 之前,匿名内部类在使用外部成员的时候,会报错并提示“Cannot refer to a non-final variable arg inside an inner class defined in a different method”文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

但是在 Java 8 之后,类似场景却没有再提示了:文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

难道是此类变量可以随便改动了吗?当然不是,当你试图修改这些变量的时候,仍然会提示错误:文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

可以看到,当试图修改基本数据类型的变量时,编译器的警告变成了“Varible 'num' is accessed from within inner class, need to be final or effectively final”,很遗憾,仍然不能修改。相比之下,Kotlin 是没有这个限制的:文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

原因分析

从表面上当然看不出什么原因,看看编译器做了什么工作吧!运行 javac命令后生成了几个 .class 文件:文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

不难推断,这个 TestInnerClass$1.class 就是匿名内部类编译后的文件,看看它反编译后是什么内容:文章源自JAVA秀-https://www.javaxiu.com/11859.html

class TestInnerClass$1 extends InnerClass {    TestInnerClass$1(TestInnerClass var1, int var2, DataBean var3) {        super(var1);        this.this$0 = var1;        this.val$num = var2;        this.val$bean = var3;    }    void doSomething() {        super.doSomething();        System.out.println("num = " + this.val$num);        System.out.println("bean name is: " + this.val$bean.name);    }}

原来,匿名内部类也会被当作普通的类处理,只不过编译器生成它构造方法的时候,除了将外部类的引用传递了过来,还将基本数据类型的变量复制了一份过来,并把引用数据类型的变量引用也传递了过来。文章源自JAVA秀-https://www.javaxiu.com/11859.html

因此,基本数据类型的变量当然不能修改了,不然就会跟外部的变量产生不一致,这样的话变量的传递也就变得毫无意义了。文章源自JAVA秀-https://www.javaxiu.com/11859.html

final 关键字除了能让类不能被继承之外,对应到这种场景,就是让变量也不能被重新赋值。文章源自JAVA秀-https://www.javaxiu.com/11859.html

情景对比

但是为什么对于 Kotlin 来说可以在匿名内部类中直接修改基本数据类型的值呢?查看 Kotlin 编译后反编译回来的内容:文章源自JAVA秀-https://www.javaxiu.com/11859.html

   public final void useNestedClass(@NotNull final TestNestedClass.DataBean bean) {      Intrinsics.checkParameterIsNotNull(bean, "bean");      final IntRef num = new IntRef();//---1      num.element = 1;//---2      String var3 = "before action, num = " + num.element;      System.out.println(var3);      <undefinedtype> nestedClass = new TestNestedClass.NestedClass() {         public void doSomething() {            num.element = 678;//---3            bean.setName("xyz");            String var1 = "num = " + num.element;            System.out.println(var1);            var1 = "bean name is: " + bean.getName();            System.out.println(var1);         }      };      nestedClass.doSomething();      String var4 = "after action, num = " + num.element;//---4      System.out.println(var4);   }

可以发现,当需要传递基本数据类型的变量时,Kotlin 编译器会将这些数据进行包装,从而由值传递变为引用传递,这样内部的修改当然就不会影响到外部了。文章源自JAVA秀-https://www.javaxiu.com/11859.html

验证一下,当变量不进行传递时,Kotlin 编译器是怎么处理的:文章源自JAVA秀-https://www.javaxiu.com/11859.html

   public final void useNestedClass(@NotNull TestNestedClass.DataBean bean) {      Intrinsics.checkParameterIsNotNull(bean, "bean");      int num = 1;      String var3 = "before action, num = " + num;      System.out.println(var3);      int num = 678;      var3 = "after action, num = " + num;      System.out.println(var3);   }

哈哈,并没有多此一举,点个赞!文章源自JAVA秀-https://www.javaxiu.com/11859.html

<END>文章源自JAVA秀-https://www.javaxiu.com/11859.html

推荐阅读:文章源自JAVA秀-https://www.javaxiu.com/11859.html

【175期】面试官:谈谈MySQL是如何解决幻读问题的?文章源自JAVA秀-https://www.javaxiu.com/11859.html

【174期】华为OD(外包)社招技术二面,总结复盘文章源自JAVA秀-https://www.javaxiu.com/11859.html

【173期】面试官:说说单点登录的三种实现方式文章源自JAVA秀-https://www.javaxiu.com/11859.html

5T技术资源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,单片机,树莓派,等等。在公众号内回复「2048」,即可免费获取!!文章源自JAVA秀-https://www.javaxiu.com/11859.html

【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

微信扫描二维码,关注我的公众号文章源自JAVA秀-https://www.javaxiu.com/11859.html

朕已阅 【176期】面试官:你知道为什么要加 final 关键字了吗?文章源自JAVA秀-https://www.javaxiu.com/11859.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定