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

best365中国官网 ⌚ 2026-08-03 18:51:51 👤 admin 👁️ 5949 ❤️ 424
终于明白 Java 为什么要加 final 关键字了!

来源:http://rrd.me/epfKR

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

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

below-java8.jpg

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

normal-use.jpg

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

img

try-to-change.jpg

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

usage-in-kt.jpg

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

generated-files.jpg

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

代码语言:javascript复制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);

}

}

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

final 关键字除了能让类不能被继承之外,对应到这种场景,就是让变量也不能被重新赋值。

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

代码语言:javascript复制 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);

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 编译器会将这些数据进行包装,从而由值传递变为引用传递,这样内部的修改当然就不会影响到外部了。

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

代码语言:javascript复制 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);

}

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

相关数据

人物設定

人物設定

白世鏡,出自現代金庸武俠小說《天龍八部》。是丐幫的執法長老,武功是纏絲擒拿手,情人是康敏,人物形象從開始的正直逐漸轉為道貌岸然

06-18 365bet现场走地盘
巩成语大全 巩字成语有哪些

巩成语大全 巩字成语有哪些

巩 康熙字典释义【寅集中】【工字部】 巩 【廣韻】與?同。(鞏)【唐韻】【正韻】居竦切【集韻】【韻會】古勇切,?音拱。【說文】以韋束

10-04 365bet赌城
淘宝店铺好评多久能看到?怎么改差评为好评?

淘宝店铺好评多久能看到?怎么改差评为好评?

在淘宝这个庞大的电商平台上,好评是商家展示商品质量和服务的窗口。那么,淘宝店铺的好评多久能看到?如何将差评改为好评?本文将为你

10-15 365bet现场走地盘
冰岛茶放几年喝,口感更佳!专家建议将冰岛茶放置几年后再饮用

冰岛茶放几年喝,口感更佳!专家建议将冰岛茶放置几年后再饮用

冰岛茶历冰岛茶放几年喝 冰岛茶是一种特别的饮品它起源于冰岛历可以追溯到几百年前。冰岛居民通过将干燥的植物杂草煮沸以 *** 此类茶它具

02-15 365bet现场走地盘
股票的三条线颜色代表什么?一文读懂

股票的三条线颜色代表什么?一文读懂

在股票交易中,我们经常会看到图表上有红、绿、蓝三种颜色的线条,它们分别代表不同的含义。对于新手投资者来说,理解这些颜色的意义是

02-17 best365中国官网
韩语词汇词根+分类记忆法epub,mobi,azw3格式电子书下载,作者:黄任

韩语词汇词根+分类记忆法epub,mobi,azw3格式电子书下载,作者:黄任

学习语言,词汇是基础。怎样记忆韩语词汇更高效、准确、轻松呢?《韩语词汇词根+分类记忆法》作者团队经过数十年的韩语教学和词法研究,

09-02 365bet赌城