问:Java中final关键字有哪些用法和作用?

final 关键字在 Java 中确实是一个重要且常用的概念,理解它对掌握 Java 语言特性很有帮助。笔者基于这篇内容,说明 final 的作用与用法,并解释编译器对 final 域的重排序规则。

1. 被 final 修饰的类不可以被继承

java 复制代码
public final class FinalClass {
    // Class body
}

// 编译错误:无法继承 final 类
// public class SubClass extends FinalClass {
// }

2. 被 final 修饰的方法不可以被重写

java 复制代码
public class ParentClass {
    public final void finalMethod() {
        System.out.println("This is a final method.");
    }
}

public class ChildClass extends ParentClass {
    // 编译错误:无法重写 final 方法
    // public void finalMethod() {
    //     System.out.println("Attempt to override final method.");
    // }
}

3. 被 final 修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。

java 复制代码
public class FinalVariableExample {
    public static void main(String[] args) {
        final int finalPrimitive = 10;
        // 编译错误:无法更改 final 变量的值
        // finalPrimitive = 20;
        
        final StringBuilder finalReference = new StringBuilder("Hello");
        // 合法:final 引用指向的对象内容可以更改
        finalReference.append(" World");
        System.out.println(finalReference); // 输出:Hello World

        // 编译错误:final 引用不能指向新的对象
        // finalReference = new StringBuilder("New String");
    }
}

4. 被 final 修饰的方法,JVM 会尝试将其内联,以提高运行效率

内联优化是由 JVM 在运行时决定的。可以理解为一个 final 方法会在编译期被认为是稳定的,JVM 有可能会将其调用替换为方法体,以减少方法调用的开销。

java 复制代码
public class FinalMethodExample {
    public final void inlineMethod() {
        System.out.println("This method might be inlined by JVM.");
    }

    public static void main(String[] args) {
        FinalMethodExample example = new FinalMethodExample();
        for (int i = 0; i < 1000; i++) {
            example.inlineMethod(); // JVM 可能会内联此方法调用
        }
    }
}

5. 被 final 修饰的常量,在编译阶段会存入常量池中

当 final 修饰基本数据类型或 String 类型,并且在编译时就能确定其值时,该值会被编译器存入常量池中。

java 复制代码
public class FinalConstantExample {
    public static final int CONSTANT_VALUE = 100;
    public static final String CONSTANT_STRING = "FINAL_STRING";

    public static void main(String[] args) {
        // 使用常量池中的值
        System.out.println(CONSTANT_VALUE);
        System.out.println(CONSTANT_STRING);
    }
}

编译器对 final 域的重排序规则

规则 1:在构造函数内对一个 final 域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序
java 复制代码
public class FinalFieldExample {
    private final int finalField;

    public FinalFieldExample(int value) {
        finalField = value; // 写入 final 域
    }

    public static void main(String[] args) {
        FinalFieldExample example = new FinalFieldExample(42);
        // 在构造函数返回前,finalField 必须已经被初始化
        System.out.println(example.finalField); // 输出:42
    }
}
规则 2:初次读一个包含 final 域的对象的引用,与随后初次读这个 final 域,这两个操作之间不能重排序
java 复制代码
public class FinalFieldInitialization {
    private final int finalField;

    public FinalFieldInitialization() {
        // 经过构造函数后,finalField 已经被初始化
        finalField = initializeField();
    }

    private int initializeField() {
        return 42;
    }

    public int getFinalField() {
        return finalField;
    }

    public static void main(String[] args) {
        FinalFieldInitialization example = new FinalFieldInitialization();
        // 确保在读取 finalField 前,对象的引用已经被正确初始化
        System.out.println(example.getFinalField()); // 输出:42
    }
}

通过这些代码示例,我们可以更清楚地理解 final 关键字在 Java 中的作用及其多种用法。掌握这些用法,有助于我们编写更健壮的代码。

相关推荐
张子夜 iiii26 分钟前
实战项目-----Python+OpenCV 实现对视频的椒盐噪声注入与实时平滑还原”
开发语言·python·opencv·计算机视觉
2301_7703737336 分钟前
Java集合
java·开发语言
哈喽姥爷44 分钟前
Spring Boot---自动配置原理和自定义Starter
java·spring boot·后端·自定义starter·自动配置原理
啊?啊?1 小时前
18 从对象内存到函数调用:C++ 虚函数表原理(继承覆盖 / 动态绑定)+ 多态实战
开发语言·c++·多态原理
bkspiderx1 小时前
C++标准库:文件流类
开发语言·c++
siy23332 小时前
[c语言日记] 数组的一种死法和两种用法
c语言·开发语言·笔记·学习·链表
njxiejing2 小时前
Python NumPy安装、导入与入门
开发语言·python·numpy
Rhys..2 小时前
Python&Flask 使用 DBUtils 创建通用连接池
开发语言·python·mysql
土了个豆子的2 小时前
04.事件中心模块
开发语言·前端·visualstudio·单例模式·c#
老华带你飞3 小时前
考研论坛平台|考研论坛小程序系统|基于java和微信小程序的考研论坛平台小程序设计与实现(源码+数据库+文档)
java·vue.js·spring boot·考研·小程序·毕设·考研论坛平台小程序