作者:guanpjhttp://www.jianshu.com/p/acc8d9a67d0c

在开发过程中,由于习惯的原因,我们可能对某种编程语言的一些特性习以为常,特别是只用一种语言作为日常开发的情况。但是当你使用超过一种语言进行开发的时候就会发现,虽然都是高级语言,但是它们之间很多特性都是不太相同的。

现象描述

在 Java 8 之前,匿名内部类在使用外部成员的时候,会报错并提示 “Cannot refer to a non-final variable arg inside an inner class defined in a different method”:

但是在 Java 8 之后,类似场景却没有再提示了:

难道是此类变量可以随便改动了吗?当然不是,当你试图修改这些变量的时候,仍然会提示错误:

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

原因分析

从表面上当然看不出什么原因,看看编译器做了什么工作吧!运行 javac 命令后生成了几个 .class 文件:

不难推断,这个 TestInnerClass$1.class 就是匿名内部类编译后的文件,看看它反编译后是什么内容:

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);}
}

原来,匿名也会被当作普通的类处理,只不过编译器生成它构造方法的时候,除了将外部类的引用传递了过来,还将基本数据类型的变量复制了一份过来,并把引用数据类型的变量引用也传递了过来。因此,基本数据类型的变量当然不能修改了,不然就会跟外部的变量产生不一致,这样的话变量的传递也就变得毫无意义了。

情景对比

但是为什么对于 Kotlin 来说可以在匿名内部类中直接修改基本数据类型的值呢?查看 Kotlin 编译后反编译回来的内容:

public final void useNestedClass(@NotNull final TestNestedClass.DataBean bean) {Intrinsics.checkParameterIsNotNull(bean, "bean");final IntRef num = new IntRef();//---1num.element = 1;//---2String var3 = "before action, num = " + num.element;System.out.println(var3);<undefinedtype> nestedClass = new TestNestedClass.NestedClass() {public void doSomething() {num.element = 678;//---3bean.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;//---4System.out.println(var4);}

可以发现,当需要传递基本数据类型的变量时,Kotlin 编译器会将这些数据进行包装,从而由值传递变为引用传递,这样内部的修改当然就不会影响到外部了。验证一下,当变量不进行传递时,Kotlin 编译器是怎么处理的:

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);}

哈哈,并没有多此一举,点个赞!

其他优质内容归纳

1. SpringBoot内容聚合

2. 面试题内容聚合

3. 设计模式内容聚合

4. Mybatis内容聚合

5. 多线程内容聚合

什么场景要用@bean_终于明白为什么要加 final 关键字了!相关推荐

  1. 终于明白 Java 为什么要加 final 关键字了!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://rrd.me/epfKR 现象描述 原因分析 ...

  2. java final关键字_终于明白 Java 为什么要加 final 关键字了!

    在开发过程中,由于习惯的原因,我们可能对某种编程语言的一些特性习以为常,特别是只用一种语言作为日常开发的情况.但是当你使用超过一种语言进行开发的时候就会发现,虽然都是高级语言,但是它们之间很多特性都是 ...

  3. 什么场景要用@bean_【176期】面试官:你知道为什么要加 final 关键字了吗?

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅 阶段汇总集 ...

  4. 终于明白那些年知其然而不知其所以然的iOS内存管理方式

    终于明白那些年知其然而不知其所以然的iOS内存管理方式 前言 从我开始学习iOS的时候,身边的朋友.网上的博客都告诉我iOS的内存管理是依靠引用计数的,然后说引用计数大于1则对象保存在内存的堆中而引用 ...

  5. 一篇文彻底理解KNN算法 - 我点了一包华子,终于明白了海伦是个好女孩

    一篇文彻底理解KNN算法 - 我点了一包华子,终于明白了海伦是个好女孩 大家好,我是W 这次我们要手撕KNN,同时自己实现KNN.当然KNN的思想很简单,所以重点会放在实现自己的KNN上.K-近邻(K ...

  6. 看完这篇文章之后,终于明白了编译到底怎么回事。

    看完这篇文章之后,终于明白了编译到底怎么回事. 1 对于同一个语句,有如下三种:高级语言.低级语言.机器语言的表示 C语言  a=b+1; 汇编语言  mov -0xc(%ebp),%eax add ...

  7. 看完这篇文章之后,终于明白了编译到底怎么回事

    看完这篇文章之后,终于明白了编译到底怎么回事. 1 对于同一个语句,有如下三种:高级语言.低级语言.机器语言的表示 C语言  a=b+1; 汇编语言  mov -0xc(%ebp),%eax add ...

  8. python可以做运动控制卡吗_今天,终于明白了运动控制器和运动控制卡的区别

    原标题:今天,终于明白了运动控制器和运动控制卡的区别 运动控制器是完整的.独立的硬件平台,运动控制卡则需要一个载体(一个系统运行平台,必须基于PC). 一.从安装使用方式来看 运动控制卡,一般是PCI ...

  9. php 对mvc的认识,【PHP】MVC框架为何这么难! 4年后终于明白了,被ThinkPHP害得!...

    [PHP]MVC框架为什么这么难!!! 4年后终于明白了,被ThinkPHP害得!! 本帖最后由 default7 于 2014-05-15 18:39:05 编辑 这个帖子送给那些被ThinkPHP ...

最新文章

  1. [转载]WPF – 使用触发器
  2. [分治] Jzoj P5807 简单的区间
  3. lsof 详解 (转载)
  4. python线程等待_python3 中 Event.wait 多线程等待
  5. 兴奋的.NET@linux-Develop
  6. 如何添加评论_亚马逊评论数据分析
  7. 手写一切(updating...)
  8. 从数据库中读取数据,创建XML文件并更新维护XML
  9. win7,win10系统激活工具下载
  10. CodeLens 显示引用
  11. 浅谈 NCSI 及其在 Linux 上的实现--IBM Developer社区文章
  12. 程序员自我学习自我培训指南
  13. 教你“强人锁男”——java并发编程的常用锁类型
  14. 实现从淘宝(天猫)定时抓取订单数据、打印电子面单并保存到ERP表中
  15. MySQL中按天、自然周、月、季度、年份统计
  16. EPLAN界面编辑背景颜色更改
  17. HFDS 常用命令 fsck 查看文件信息和block位置信息
  18. c语言中如果产量的隐藏类型是,如果随着产量的增加,生产函数首先表现出边际产量增加,然后表现出边际产量递减,那么相应的边际成本曲线将 答案:是U形的...
  19. app.json: [“subpackages“][0][“root“] 字段需为 目录
  20. FFA interface

热门文章

  1. python菜鸟工具-Python3 教程
  2. 学好python能干嘛-普通人学Python有用吗?学完能做什么?
  3. 没有c语言基础可以学python吗-学习Python之前需要先学习一下c语言吗?
  4. php与jpython-Ruby on Rails VS PHP VS Python
  5. 学会python之后-python学会基础语法之后,如何提高?
  6. python到底干嘛的-Python是干嘛的?可以做什么?老男孩Python培训班
  7. python经典案例-Python经典实例
  8. python在日常工作处理中的应用-谈谈Python在工作中的应用
  9. Makefile中常用的函数
  10. css input[type=file] 样式美化,input上传按钮美化