final关键字用于声明不可修改的变量、方法或类;基本类型final变量值不可变,引用类型仅引用不可变而对象内容可能可变,实例final字段须在构造中赋值,仅static final基本类型或string字面量才是编译期常量。

final 关键字在 Java 中用于声明不可修改的变量、方法或类。若想声明一个“不可修改的常量”,核心是用 final 修饰基本类型或引用类型变量,并在声明时或构造过程中**明确赋值一次且仅一次**。
基本类型常量:值不可变
对 int、double、boolean 等基本类型,使用 final 后,其值一旦初始化,就无法再被更改:
- 推荐搭配 static 和大写命名(符合常量命名规范)
- 必须在声明时或静态初始化块中完成赋值
public class Config {
public static final int MAX_RETRY = 3; // ✅ 编译期常量
public static final double PI = 3.14159; // ✅
public static final boolean DEBUG = true; // ✅
}
引用类型常量:引用不可变,对象内容可能可变
final 修饰引用类型(如 String、List、自定义对象)时,**只保证该变量始终指向同一个对象,不阻止对象内部状态改变**:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- String 是不可变类,所以 final String 真正“内容不可变”
- ArrayList 被 final 修饰后,不能重新赋值为另一个 List,但可以 add/remove 元素
- 若需真正“不可变对象”,应选用不可变类(如 Collections.unmodifiableList)或自行设计不可变类
public class Constants {
public static final String NAME = "Java"; // ✅ 安全,String 不可变
public static final List<string> NAMES = new ArrayList(); // ⚠️ 引用不可变,但内容可变
// 正确做法:提供不可变视图
public static final List<string> FIXED_NAMES =
Collections.unmodifiableList(Arrays.asList("A", "B")); // ✅ 内容也不可变
}</string></string>
实例常量:在构造过程中赋值
非 static 的 final 字段属于实例常量,必须在每个构造方法中确保被赋值(或通过初始化块):
- 不能留空,否则编译报错 “variable might not have been initialized”
- 可在声明处直接初始化,也可在所有构造方法中显式赋值
public class User {
private final String id;
private final String name;
public User(String id, String name) {
this.id = id; // ✅ 必须在此处或声明时赋值
this.name = name;
}
// 若有多个构造方法,每个都必须给 final 字段赋值
}
注意:final ≠ 编译时常量(只有满足特定条件才是)
只有同时满足以下三点,final 变量才是“编译期常量”(会被内联优化):
- 被 static final 修饰
- 类型是基本类型或 String
- 用编译期可确定的常量表达式初始化(如字面量、其他编译期常量运算)
static final int A = 10; // ✅ 编译期常量 static final String S = "hello" + " world"; // ✅ static final int B = System.currentTimeMillis(); // ❌ 运行期值,不是编译期常量
不复杂但容易忽略:final 常量的关键不在“写法”,而在“何时赋值”和“是否真正不可变”。基本类型放心用;引用类型要多看一眼对象本身是否可变。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










