Java final/finally/finalize与四种引用全解析
final是关键字,用于定义不可变类、方法或变量;finally是异常处理代码块,确保资源释放;finalize是Object类方法,已被废弃。对象引用分为强、软、弱、虚四种,强引用永不回收,软引用内存不足时回收,弱引用下次GC即回收,虚引用用于跟踪对象回收。
前言
在Java的学习与开发中,有些核心知识点是绕不开的,例如final、finally、finalize三者的区别,以及对象的四种引用类型(强引用、软引用、弱引用、虚引用)。这些内容不仅是面试中的高频考点,更是深入理解Java内存管理、异常处理机制以及ThreadLocal底层原理的关键所在。
本文将从定义、用法、代码示例、对比分析等多个维度,系统讲解这两块核心知识。目标是让读者在面试时能够从容应答,在实际编码中能够正确运用。
一、核心区分:final、finally、finalize 详解
1.1 final 关键字:不可变的强制约束
final是Java中的一个关键字,用于对“不可变性”进行强制约束。具体包含三种用法:
- 修饰类:该类不能被继承,例如
String、Integer等常用类。 - 修饰方法:该方法不能被子类重写,确保核心逻辑的稳定性。
- 修饰变量:该变量变为常量,仅允许赋值一次。
// 修饰类
final class Demo{}
// 修饰方法
public final void test(){}
// 修饰变量
final int a = 10;
1.2 finally 代码块:异常处理中的必执行段
finally属于Java异常处理机制的重要组成部分,是 try-catch 语句块中的特殊代码段。其核心特点是:无论是否发生异常,该代码段都会被执行。
finally的主要用途是资源清理与释放,典型场景包括:
- 关闭IO流
- 关闭数据库连接
- 释放锁资源
这些操作若未执行,将导致资源泄漏。finally相当于一道安全屏障,确保资源释放操作能够兜底执行。
try {
// 业务逻辑代码
} catch(Exception e) {
// 异常处理逻辑
} finally {
// 必须执行:释放资源
}
1.3 finalize 方法:GC回收前的回调机制
finalize是 Object 类中定义的一个方法,并非由开发者主动调用,而是由垃圾回收器(GC)在回收对象前自动触发。其原始设计意图是让对象在被回收前有机会释放额外持有的资源。
目前,该方法已被官方标记为废弃。不推荐在实际开发中使用或重写,主要原因在于执行时机不可控且性能表现不佳。
@Override
protected void finalize() throws Throwable {
// GC回收前操作(不推荐使用)
}
1.4 三者核心对比表
| 关键字 | 类型 | 作用 | 使用场景 |
|---|---|---|---|
| final | 关键字 | 不可变、不可继承、不可重写 | 定义常量、工具类 |
| finally | 代码块 | 异常处理中的必执行段 | 资源释放与清理 |
| finalize | 方法 | GC回收前自动调用 | 已废弃,不推荐使用 |
二、Java对象的四种引用类型详解
从JVM 1.2版本开始,Java对对象的引用进行了更精细的划分,共分为四种类型。这种设计在“内存充裕”与“内存紧张”之间提供了一套灵活的控制策略。
2.1 强引用:永不回收
强引用是Java中最常见的引用类型。只要引用存在,即对象被变量持有,GC就绝不会回收该对象。
Object obj = new Object(); // 强引用
强引用的核心特征:
- 内存不足时,也不会被回收。
- 宁可抛出OOM(OutOfMemoryError,内存溢出错误),也要保持对象存活。
因此,在使用强引用时需注意:若对象生命周期较长,应避免引用链不必要地延长,以防内存占用过高。
2.2 软引用:内存不足时回收
软引用对GC的处理较为“温和”——只有当内存确实紧张时,才会被回收。这使得软引用非常适合用于缓存场景。在内存充裕时,对象得以保留;在OOM发生前,才被清理释放。
Object obj = new Object(); SoftReference
典型应用场景:
- 图片缓存(如从网络加载后暂存内存)
- 网页缓存
- 不常驻内存但希望尽量复用的数据
2.3 弱引用:下次GC必回收
弱引用的生命周期更为短暂——只要GC启动,其所指向的对象就会被回收。对象存活时间仅为两次GC之间的短暂间隙。
Object obj = new Object(); WeakReference
这里有一个核心重点需要特别关注:ThreadLocal 的底层实现中,其key使用的正是弱引用。
static class Entry extends WeakReference> { Object value; Entry(ThreadLocal> k, Object v) { super(k); value = v; } }
如此设计的目的在于防止内存泄漏。当外部对 ThreadLocal 对象的强引用消失后,ThreadLocalMap 中的key会随着GC自动回收,避免Entry长期占用内存。
2.4 虚引用:随时回收,无法获取对象
虚引用是四种引用中最弱的一种。其 get() 方法始终返回 null,开发者无法通过虚引用获取实际对象。虚引用的价值在于“监听”机制。它必须配合引用队列(ReferenceQueue)使用,当对象被回收时,虚引用会被放入队列,从而让外部感知对象已被清理。
ReferenceQueue queue = new ReferenceQueue(); PhantomReference
核心用途:
- 监听对象被GC回收的准确时机
- 管理堆外内存(如Netty等框架中的应用)
三、四种引用回收时机流程图
为更直观地理解四种引用在不同内存压力下的存活与回收状态,可参考下图:
四、高频面试题标准答案
以下为面试中常见问题的标准回答,可直接背诵掌握。
4.1 final、finally、finalize 有何区别?
- final 是关键字,用于定义不可变性(类、方法、变量)。
- finally 是异常处理结构中的代码块,保证无论如何都会执行,常用于资源释放。
- finalize 是Object类中的方法,在GC回收对象前被调用,目前已废弃。
4.2 四种引用分别是什么?
强引用、软引用、弱引用、虚引用。记忆口诀:强软弱虚,回收力度依次增强。
4.3 ThreadLocal 为何使用弱引用?
为防止内存泄漏。ThreadLocalMap的key采用弱引用,当外部对ThreadLocal对象的强引用置为null后,key在下一次GC时会被自动回收,避免Entry长期占用内存导致泄漏。
结束语
final、finally、finalize以及对象的四种引用类型,既是Java的基础知识,也是JVM内存管理的核心内容。深入理解这些概念,有助于编写更健壮的代码,减少潜在问题,并在面试中展现扎实的技术功底。
