首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java final/finally/finalize 三大关键字深度辨析

     編輯:Java 相關知識

一字之差,天壤之别

final、finally、finalize 是 Java 基础面试必考「三兄弟」,虽名似但职责截然不同。本文从语法、语义、字节码、实战四个维度彻底澄清。

final:不可变的契约

修饰目标语义典型场景
类不可被继承String、Wrapper 类、工具类
方法不可被重写模板方法模式固定骨架、安全敏感操作
变量(基本类型)值不可变常量定义 final double PI = 3.14
变量(引用类型)引用不可变(指向对象不可变),但对象内部状态可变final List<String> list = new ArrayList<>(); list.add("ok"); // 合法

编译期常量折叠:final 修饰的基本类型/String 编译期确值,直接内联到调用处字节码,性能微增。

finally:资源释放的最后防线

try (Resource res = acquire()) {  // Java 7+ try-with-resources 自动 close
    use(res);
} catch (Exception e) {
    handle(e);
} finally {
    // 无论正常/异常/return 都会执行
    cleanup(); 
}

执行时机保证

  • ✅ try 正常结束
  • ✅ catch 捕获异常后
  • ✅ catch 未捕获异常向上抛出前
  • ✅ try/catch 中 return/break/continue 前
  • ❌ System.exit(0) 终止 JVM
  • ❌ 死循环/死锁导致线程永不离开 try
  • ❌ 宿主线程被 Thread.stop() 强制终止(已废弃)

经典陷阱:finally 中 return 覆盖异常

public int test() {
    try { return 1; }
    finally { return 2; } // 方法返回 2,原返回值/异常被吞没!
}

禁忌:finally 块中严禁使用 return/throw,否则异常丢失、调试极难。

finalize:已废弃的终结者

@Deprecated(since="9")
protected void finalize() throws Throwable { ... }

设计缺陷

  • 不可预测调用时机:GC 触发才调用,可能永不执行
  • 性能损耗:finalize 对象需两次 GC 才能回收,增加 GC 压力
  • 线程安全风险:finalize 运行在 Finalizer 线程,可能复活对象导致并发问题
  • 无序性:对象间 finalize 顺序不定,依赖关系易破坏

现代替代方案

  1. try-with-resources (Java 7+):实现 AutoCloseable,编译器自动生成 finally close 代码
  2. Cleaner API (Java 9+):Cleaner.create(obj, cleaningAction),基于幻象引用,可控、可取消、线程安全
  3. 显式 close()/shutdown():生命周期由业务代码显式控制,最可靠

实战对比:Socket 资源释放演进

// 1. 传统模式(易泄漏)
Socket s = new Socket();
try { use(s); } 
catch (IOException e) { s.close(); throw e; }
s.close(); // 重复代码,异常路径易漏

// 2. finally 兜底(冗长)
Socket s = new Socket();
try { use(s); }
finally { 
    if (s != null) try { s.close(); } catch (IOException ignored) {}
}

// 3. try-with-resources (推荐)
try (Socket s = new Socket()) {
    use(s);
} // 编译器自动生成 null 检查 + 异常抑制的 close()

// 4. Cleaner (库/框架级)
Cleaner cleaner = Cleaner.create();
Socket s = new Socket();
cleaner.register(s, () -> { try { s.close(); } catch (IOException e) { log.error(e); } });
// 业务代码无感,Cleaner 统一管理

总结

final 定约不可变性,finally 兜底资源释放,finalize 是历史包袱已被 AutoCloseable/Cleaner 取代。掌握 try-with-resources 与 Cleaner,写出不泄漏、可维护的资源管理代码,是现代 Java 程序员必备基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved