final、finally和 finalize的区别
| 特性 | final (关键字) | finally (关键字) | finalize() (方法) |
|---|---|---|---|
| 实现方式 | 修饰类、方法或变量 | 与 try-catch块配合使用 | 在类中重写 Object的 finalize()方法 |
| 核心作用 | 限制继承、重写或修改 | 确保代码块必然执行(如资源释放) |
对象被垃圾回收前的清理操作(已废弃) |
| 执行时机 | 编译时检查 | 运行时在 try-catch后执行 | 不确定(由GC触发,不保证一定执行) |
| 是否可控制 | 开发者显式声明 | 开发者显式编写 | 由JVM自动调用 |
| 现代替代方案 | 无(仍是重要关键字) | 无(仍是异常处理核心) | try-with-resources或 AutoCloseable接口 |
| 线程安全 | 被 final修饰的变量是线程安全的(不可变) | 与线程无关 | 不保证线程安全(可能被多线程环境下的GC调用) |
final关键字在不同场景下的应用
final应用于类
作用:禁止其他类继承该类
特点:
- 该类不能被任何其他类继承(不能有子类)
- 类中所有方法隐式为 final(不能被子类重写)
- 常用于设计不可变类或工具类
典型应用:
- JDK中的String、Integer等包装类都是final类
- 工具类如Arrays、Collections等
final应用于方法
作用:禁止子类重写该方法
特点:
- 子类不能重写(override)该方法
- 但可以被继承和调用
- 常用于防止核心算法被修改
典型应用:
模板方法模式中的固定步骤
安全相关的方法(如加密算法)
final应用于变量
成员变量
特点:
- 必须在声明时或构造函数中初始化
- 初始化后不能被修改
- 如果是引用类型,引用不可变(对象内容可能可变)
java
class Circle {
private final double radius; // final成员变量
public Circle(double r) {
this.radius = r; // 构造函数中初始化
}
// 编译错误:不能在普通方法中修改final变量
// public void setRadius(double r) { this.radius = r; }
}
静态变量(类常量)
规范:
- 命名全大写,单词间用下划线连接
- 基本类型直接作为常量使用
- 引用类型应使用不可变对象
java
public static final int MAX_RETRY_COUNT = 3;// 最大重试次数
public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30);// 默认超时时间
public static final List<String> SUPPORTED_LANGUAGES =
Collections.unmodifiableList(Arrays.asList("EN", "ZH", "JP"));// Java 提供了 Collections.unmodifiableList()方法,使集合变成 只读
局部变量
特点:
- 一旦赋值后不能被修改
- 可以延迟初始化(不需要声明时立即赋值)
java
public class Example {
// 成员变量(实例变量)
int num1; // 默认 0
static int num2; // 默认 0
public void method() {
// 局部变量(必须手动初始化)
int num3;
num3 = 10;
System.out.println(num3); // 正确
// int num4;
// System.out.println(num4); // 错误:num4 未初始化
}
}
final应用于参数
作用:
- 防止参数在方法内被意外修改
- 明确表达参数不应改变的意图
java
public class Main {
public static void main(String[] args) {
printName("Bob"); // 输出:Name: Bob
}
public static void printName(final String name) {
// name = "Alice"; // ❌ 编译错误:不能修改 final 参数
System.out.println("Name: " + name);
}
}
final应用于对象
- final只保证引用不变,不保证对象内容不变
java
public class FinalObjectDemo {
public static void main(String[] args) {
// 创建final对象引用
final Person person = new Person("Alice", 25);
// 可以修改对象内部状态
person.setAge(26); // ✅ 允许
System.out.println(person); // 输出: Person[name=Alice, age=26]
// person = new Person("Bob", 30); // ❌ 编译错误:不能修改final引用
}
}