Java中的final关键字

本文深入解析final关键字在Java中的三种用途:修饰类、方法和变量。详细介绍了final类防止继承、final方法禁止重写以及final变量确保只读的特性,通过实例展示了如何在实际编程中正确运用final关键字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

final关键字可以修饰类、方法、变量。本质作用可以理解为“声明被修饰对象只读”,不同用法对应不同的具体解释。

final类

final类表示该类是完整(可理解为最终版本)的,禁止扩展。final标记会写入class文件的类定义中,在编译期检查,如果发现上游extends了一个final类后,则编译失败,从语法上保证不能extends一个final类。

final类经常用于不可变类的构造中:如果不使用final修饰,且有对子类可见的可变成员变量,则extends该“不可变类”后,子类就变成了可变类。考虑到多态的存在,这种“歧义”非常危险。详见:实现不可变类时如何禁止子类化?

例:String类、Interger类等:

public final class String

final方法

与final类的语义相似,final方法表示该方法是完整的,禁止重写。final标记会写入class文件的成员方法定义中,在编译期检查,如果发现继承链上游有函数签名相同的final方法(重写),则编译失败,从语法上保证不能重写一个final方法;同时,在编译期完成对final方法的解析(静态绑定)。

例:com.sun.org.apache.bcel.internal.classfile.Signature中的dump方法:

public final void dump(DataOutputStream file) throws IOException
{
  super.dump(file);
  file.writeShort(signature_index);
}

final变量

final成员变量

final成员变量体现了最直观的final语义:final成员变量表示该成员变量只读(在第一次赋值后就不能再修改)。final标记会写入class文件的成员变量定义中,在编译器和运行期都会进行检查,如果发现第二次修改就编译失败或抛出异常。

如果想实现不可变类,通常建议尽量使用final修饰每一个成员变量(延迟初始化等会违背这一建议)。

如果final成员变量的初始化被收集到该类的构造方法中,则final成员变量初始化之前的变量通常具有内存可见性,但这一性质并不容易应用,不建议利用。详见:一文解决内存屏障

例:Integer#value:

private final int value;
public Integer(int value) {
    this.value = value;
}

显式的用构造方法初始化final成员变量。

常量

如果在成员变量声明时完成初始化(第一次赋值),则该成员变量被JVM视作常量。

对于编译期能确定初始值的常量(如final int a = 1;),通常能通过常量折叠常量传播等技术,在编译期完成常量的优化和解析。

例:Integer.SIZEInteger.BYTES

@Native public static final int SIZE = 32;
public static final int BYTES = SIZE / Byte.SIZE;

final局部变量

final局部变量也表示该局部变量只读,但与final成员变量不同,final局部变量只是java中的语法糖,局部变量上的final修饰并不会写入class文件,更无法出现在运行期。如果局部变量被final修饰,则编译器在编译时会检查该变量是否有可能发生第二次修改,有可能就编译失败;否则,消除final修饰。

例:

final局部变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序员-张凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值