核心含义
final 译为 "最终的、不可改变的",在 Java 中它的核心作用是限制修改 ------ 被 final 修饰的元素(类、方法、变量)会失去 "可修改 / 可扩展" 的特性,变成 "不可变 / 不可扩展" 的状态。
简单来说,final 的核心就是 "锁死":
- 修饰类:类不可被继承;
- 修饰方法:方法不可被重写;
- 修饰变量:变量的值 / 引用不可被修改。
具体用法
1. 修饰类:类不可被继承
定义与特点
- 用
final修饰的类,称为 "最终类",不能被任何其他类继承(无法创建其子类)。 - 设计目的:保证类的完整性和安全性,防止子类修改父类的核心逻辑。
代码示例
java
// final 修饰类:String 是 Java 中典型的 final 类(源码中 public final class String)
final class FinalClass {
public void sayHello() {
System.out.println("我是 final 类的方法");
}
}
// 错误:无法继承 final 类,编译报错
// class SubClass extends FinalClass {
// // 子类试图扩展 final 类,不允许
// }
public class FinalDemo {
public static void main(String[] args) {
FinalClass fc = new FinalClass();
fc.sayHello(); // 正常调用方法(final 类只是不能被继承,对象可以正常创建和使用)
}
}

常见使用场景
- 核心工具类:如
java.lang.String、java.lang.Integer(包装类)、java.lang.Math,这些类的逻辑是 Java 核心基础,不允许子类修改; - 安全类:涉及敏感逻辑(如加密、权限控制)的类,防止子类篡改核心逻辑。
2. 修饰方法:方法不可被重写
定义与特点
- 用
final修饰的方法,称为 "最终方法",子类不能重写(Override) 这个方法(但可以重载)。 - 设计目的:保护父类的核心方法逻辑不被子类修改,同时提升方法调用效率(JVM 可能对 final 方法做内联优化)。
代码示例
java
class ParentClass {
// final 修饰方法:不可被重写
public final void finalMethod() {
System.out.println("我是父类的 final 方法");
}
// 普通方法:可被重写
public void normalMethod() {
System.out.println("我是父类的普通方法");
}
}
class ChildClass extends ParentClass {
// 错误:无法重写 final 方法,编译报错
// @Override
// public void finalMethod() {
// System.out.println("子类试图重写 final 方法");
// }
// 正确:重写普通方法
@Override
public void normalMethod() {
System.out.println("子类重写了普通方法");
}
// 正确:重载 final 方法(参数列表不同,不是重写)
public final void finalMethod(int num) {
System.out.println("子类重载了 final 方法,参数:" + num);
}
}
public class FinalMethodDemo {
public static void main(String[] args) {
ChildClass child = new ChildClass();
child.finalMethod(); // 调用父类的 final 方法,输出:我是父类的 final 方法
child.finalMethod(100); // 调用子类重载的 final 方法,输出:子类重载了 final 方法,参数:100
child.normalMethod(); // 调用子类重写的普通方法,输出:子类重写了普通方法
}
}

关键区分:重写 vs 重载
- 重写(Override) :子类方法与父类方法的「方法名、参数列表、返回值」完全一致 →
final方法禁止这种操作; - 重载(Overload) :子类 / 同一类中方法名相同,参数列表不同 →
final方法允许这种操作。
3. 修饰变量:变量不可被修改
这是 final 最常用的用法,也是最容易混淆的部分,需分「基本类型变量」和「引用类型变量」两种情况理解。
核心规则

代码示例:基本类型变量
- final 修饰基本类型变量:值不可改
- final 修饰的局部变量可以先声明后赋值(但只能赋值一次)
java
public class FinalBasicVar {
public static void main(String[] args) {
// final 修饰基本类型变量:值不可改
final int num = 10;
System.out.println(num); // 输出:10
// 错误:无法为最终变量 num 分配值,编译报错
// num = 20;
// final 修饰的局部变量可以先声明后赋值(但只能赋值一次)
final double pi;
pi = 3.1415926; // 第一次赋值,合法
// pi = 3.14; // 错误:第二次赋值,编译报错
System.out.println(pi); // 输出:3.1415926
}
}

代码示例:引用类型变量
- final 修饰引用类型变量:引用不可改,对象内容可改
java
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class FinalReferenceVar {
public static void main(String[] args) {
// final 修饰引用类型变量:引用不可改,对象内容可改
final Person p = new Person("张三");
System.out.println(p.getName()); // 输出:张三
// 正确:修改对象的内容(引用地址没变)
p.setName("李四");
System.out.println(p.getName()); // 输出:李四
// 错误:修改引用地址(指向新对象),编译报错
// p = new Person("王五");
// 同理:final 修饰数组(引用类型)
final int[] arr = {1, 2, 3};
arr[0] = 100; // 正确:修改数组内容
System.out.println(arr[0]); // 输出:100
// arr = new int[]{4,5,6}; // 错误:修改数组引用
}
}

final 变量的赋值时机(必须赋值,且仅一次)
final 变量必须在「声明时 / 构造方法 / 初始化块」中完成赋值,否则编译报错,具体分为:
- 成员变量(类中声明) :
- 方式 1:声明时直接赋值(推荐):
final int num = 10;; - 方式 2:在构造代码块中赋值;
- 方式 3:在构造方法中赋值(每个构造方法都要赋值,避免遗漏)。
- 方式 1:声明时直接赋值(推荐):
- 局部变量(方法中声明):声明时可暂不赋值,但使用前必须赋值,且仅能赋值一次。
代码示例:成员变量的赋值时机
java
public class FinalVarInit {
// 方式1:声明时赋值(推荐)
final int a = 10;
// 方式2:构造代码块中赋值
final int b;
{
b = 20;
}
// 方式3:构造方法中赋值(每个构造方法都要赋值)
final int c;
public FinalVarInit() {
c = 30;
}
public FinalVarInit(int c) {
this.c = c;
}
public static void main(String[] args) {
FinalVarInit demo1 = new FinalVarInit();
System.out.println(demo1.a + "," + demo1.b + "," + demo1.c); // 输出:10,20,30
FinalVarInit demo2 = new FinalVarInit(40);
System.out.println(demo2.a + "," + demo2.b + "," + demo2.c); // 输出:10,20,40
}
}

静态 final 变量(常量)
**static + final**组合修饰的变量,称为 "静态常量"(也叫类常量),是 Java 中定义常量的标准方式:
- 属于类,而非对象,所有对象共享;
- 必须在声明时或静态代码块中赋值(不能在构造方法 / 构造代码块中赋值);
- 命名规范:全大写,单词间用下划线分隔(如
public static final double PI = 3.1415926;)。
代码示例:静态常量
java
public class FinalStaticVar {
// 静态常量:声明时赋值(推荐)
public static final String SCHOOL_NAME = "北京大学";
// 静态常量:静态代码块中赋值(适合复杂初始化,如读取配置)
public static final int MAX_NUM;
static {
MAX_NUM = 1000;
}
public static void main(String[] args) {
// 直接通过类名访问静态常量
System.out.println(FinalStaticVar.SCHOOL_NAME); // 输出:北京大学
System.out.println(FinalStaticVar.MAX_NUM); // 输出:1000
}
}

常见误区
- 误区 1 :final 修饰的引用变量,指向的对象内容也不可改。→ 错误:final 仅限制「引用地址」不可改,对象 / 数组的内容可以正常修改(如
p.setName("李四")合法)。 - 误区 2:final 方法不能被重载。→ 错误:final 禁止的是「重写(Override)」,允许「重载(Overload)」(参数列表不同即可)。
- 误区 3:final 变量必须声明时赋值。→ 错误:成员变量可在构造代码块 / 构造方法中赋值,局部变量可在使用前赋值(但都仅能赋值一次)。
- 误区 4 :final 类中的方法自动是 final 的。→ 正确 ,但无需显式加 final:final 类不能被继承,其方法自然无法被重写,因此默认是 final 的(显式加 final 也可以,但没必要)。
实际应用场景
- 定义常量 :
static final组合,如Math.PI、Integer.MAX_VALUE; - 保护核心逻辑:修饰类 / 方法,防止子类篡改(如 String 类、父类的核心业务方法);
- 线程安全:final 变量赋值后不可改,多线程环境下无需担心被修改,提升线程安全性;
- 方法参数 :修饰方法参数,防止方法内修改参数值(如
public void method(final int num)); - 优化性能:JVM 对 final 方法 / 变量可能做优化(如内联 final 方法),提升执行效率。
总结
final的核心是「限制修改」:修饰类→不可继承,修饰方法→不可重写,修饰变量→值 / 引用不可改;- 关键区分:final 基本类型变量「值不可改」,final 引用类型变量「引用不可改,内容可改」;
- 常用组合:
static + final定义静态常量(Java 常量的标准写法); - 赋值规则:final 变量必须赋值且仅赋值一次,成员变量可在声明 / 构造代码块 / 构造方法中赋值,静态 final 变量仅能在声明 / 静态代码块中赋值。
掌握 final 的关键是理解 "不可改" 的具体范围 ------ 不同元素(类 / 方法 / 变量)的 "不可改" 含义不同,避免一概而论。