Java基础(十一):关键字final详解
Java基础系列文章
Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建
Java基础(二):八种基本数据类型详解
Java基础(三):逻辑运算符详解
Java基础(四):位运算符详解
Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南
Java基础(六):数组全面解析
Java基础(七): 面向过程与面向对象、类与对象、成员变量与局部变量、值传递与引用传递、方法重载与方法重写
Java基础(八):封装、继承、多态与关键字this、super详解
Java基础(九):Object核心类深度剖析
Java基础(十):关键字static详解
Java基础(十一):关键字final详解
目录
- 一、final概述
- 二、final修饰变量
- 1、final基本类型变量
- 2、final引用类型变量
- 3、final变量的初始化时机
- 三、final修饰方法
- 四、final修饰类
- 五、final修饰参数
- 六、final在并发编程中的应用
一、final概述
final
是Java中的一个修饰符,可以用来修饰类
、方法
和变量
。它的核心含义是"不可改变的"
- final变量:一旦初始化就
不能重新赋值
- final方法:
不能被子类重写
- final类:
不能被继承
- final变量:一旦初始化就
二、final修饰变量
1、final基本类型变量
- 当final修饰基本类型变量时,该变量的值一旦被初始化后就不能再改变
final int MAX_VALUE = 100;
// MAX_VALUE = 200; // 编译错误,不能修改final变量的值
特点:
- 必须在声明时或构造方法/静态块中初始化
- 一旦赋值后不能再修改
- 对于基本类型,值本身不可变
2、final引用类型变量
- 当final修饰引用类型变量时,
引用本身不可变
(即不能指向其他对象),但对象的内容可以改变
final List<String> names = new ArrayList<>();
names.add("Alice"); // 允许,修改对象内容
// names = new ArrayList<>(); // 编译错误,不能改变引用
特点:
- 引用不可变 ≠ 对象不可变
- final只保证引用不变,不保证被引用对象的内容不变
3、final变量的初始化时机
- 对于实例变量:可以在
声明时
、构造代码块
或构造方法
中初始化 - 对于静态变量:可以在
声明时
或静态初始化块
中初始化
public class Example {// 实例变量final int instanceVar1 = 10; // 声明时初始化final int instanceVar2;final int instanceVar3;{instanceVar2 = 20; // 实例初始化块(构造代码块)初始化}Example() {instanceVar3 = 30; // 构造方法中初始化}// 静态变量static final int STATIC_VAR1 = 10; // 声明时初始化static final int STATIC_VAR2;static {STATIC_VAR2 = 20; // 静态初始化块中初始化}
}
三、final修饰方法
- 当final修饰方法时,该方法不能被子类重写(override)
class Parent {public final void forbiddenMethod() {System.out.println("我不能被重写");}public void normalMethod() {System.out.println("我可以被重写");}
}class Child extends Parent {// @Override// public void forbiddenMethod() { } // 编译错误:不能重写final方法@Overridepublic void normalMethod() {System.out.println("父类方法被重写了");}
}
设计考虑:
- 防止子类修改关键方法:确保方法的行为不会被子类改变
- 常将框架中的关键方法声明为final
- 当不希望子类改变特定行为时使用
- JVM可以对final方法进行
内联优化
:直接将方法体插入调用处,减少方法调用的开销
四、final修饰类
- 当final修饰类时,该类不能被继承
final class StringUtils {public static boolean isEmpty(String str) {return str == null || str.trim().isEmpty();}
}// class ExtendedUtils extends StringUtils { } // 编译错误:不能继承final类
常见的final类:
- String
- Integer
- Double
- Math
- System
设计考虑:
不可变类
:如String类,确保对象状态不会被改变安全性
:防止通过继承破坏类的安全性或不变性设计意图
:明确表示该类不应有子类工具类
:如Math,只包含静态方法,不需要实例化或继承
五、final修饰参数
public void process(final int param1, final List<String> param2) {// param1 = 10; // 编译错误// param2 = new ArrayList<>(); // 编译错误param2.add("value"); // 允许,修改对象内容
}
设计考虑:
- 防止方法内部意外修改参数引用
- 提高代码可读性,明确参数不应被重新赋值
六、final在并发编程中的应用
final
字段在并发编程中非常重要,因为JVM保证final
字段的初始化安全
class SafePublication {final int safeValue;int unsafeValue;public SafePublication(int value) {this.safeValue = value; // 正确初始化this.unsafeValue = value; // 可能发生重排序// 在构造函数返回后,safeValue对所有线程立即可见}public int getSafeValue() {return safeValue; // 总是能看到正确初始化的值}public int getUnsafeValue() {return unsafeValue; // 可能看到默认值0}
}
Java内存模型对final字段有特殊规定:
- 在构造函数中对final字段的写入,与随后将被构造对象的引用赋值给一个引用变量,这两个操作
不能重排序
- 初次读包含final字段的对象的引用,与随后初次读这个final字段,这两个操作
不能重排序
这意味着:正确构造的对象的final字段,对于所有线程都是可见的,无需额外的同步措施