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

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

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

现象描述

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

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

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

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

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

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

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

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

原因分析

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

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

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

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

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

情景对比

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

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

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

验证一下,当变量不进行传递时,Kotlin 编译器是怎么处理的:

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

 

 

责任编辑:庞桂玉 来源: 简书
相关推荐

2019-09-09 08:28:48

互联网数据磁盘

2020-08-23 11:03:24

Python开发void

2020-08-10 08:00:13

JavaFinal关键字

2021-01-05 10:26:50

鸿蒙Javafinal

2009-12-08 18:02:06

PHP final关键

2020-04-25 20:20:28

苹果库克手机

2012-03-13 14:41:41

JavaJVM

2024-01-15 10:41:31

C++关键字开发

2022-06-28 22:27:38

数字化转型

2019-09-20 13:16:22

手机摄像头三摄

2020-06-16 08:17:11

代码空格开发

2022-11-15 08:35:00

SQLNOLOCK数据

2023-04-06 08:43:29

SQLWITH(NOLOCK

2021-01-07 11:10:47

关键字

2021-01-26 07:20:26

Final关键字类变量

2021-02-17 13:35:17

finalgetJava

2022-06-09 08:32:21

SQLNOLOCKWITH

2021-09-14 10:48:13

SQL Nolock代码

2021-01-17 22:55:08

人工智能机器学习深度学习

2021-01-26 15:34:19

人工智能深度学习机器学习
点赞
收藏

51CTO技术栈公众号