Java final/finally/finalize与四种引用全解析

作者:技术拾光

时间:2026-07-18

浏览:401

final是关键字,用于定义不可变类、方法或变量;finally是异常处理代码块,确保资源释放;finalize是Object类方法,已被废弃。对象引用分为强、软、弱、虚四种,强引用永不回收,软引用内存不足时回收,弱引用下次GC即回收,虚引用用于跟踪对象回收。

文章目录

前言

在Java的学习与开发中,有些核心知识点是绕不开的,例如final、finally、finalize三者的区别,以及对象的四种引用类型(强引用、软引用、弱引用、虚引用)。这些内容不仅是面试中的高频考点,更是深入理解Java内存管理、异常处理机制以及ThreadLocal底层原理的关键所在。

本文将从定义、用法、代码示例、对比分析等多个维度,系统讲解这两块核心知识。目标是让读者在面试时能够从容应答,在实际编码中能够正确运用。

一、核心区分:final、finally、finalize 详解

1.1 final 关键字:不可变的强制约束

final是Java中的一个关键字,用于对“不可变性”进行强制约束。具体包含三种用法:

  1. 修饰类:该类不能被继承,例如 String、Integer 等常用类。
  2. 修饰方法:该方法不能被子类重写,确保核心逻辑的稳定性。
  3. 修饰变量:该变量变为常量,仅允许赋值一次。
// 修饰类
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 sf = new SoftReference<>(obj);
obj = null;
sf.get(); // 内存充足时返回对象,内存不足时返回null

典型应用场景:

  • 图片缓存(如从网络加载后暂存内存)
  • 网页缓存
  • 不常驻内存但希望尽量复用的数据

2.3 弱引用:下次GC必回收

弱引用的生命周期更为短暂——只要GC启动,其所指向的对象就会被回收。对象存活时间仅为两次GC之间的短暂间隙。

Object obj = new Object();
WeakReference wf = new WeakReference<>(obj);
obj = null;
wf.get(); // GC前有值,GC后为null

这里有一个核心重点需要特别关注: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 pf = new PhantomReference<>(obj, queue);

核心用途:

  • 监听对象被GC回收的准确时机
  • 管理堆外内存(如Netty等框架中的应用)

三、四种引用回收时机流程图

为更直观地理解四种引用在不同内存压力下的存活与回收状态,可参考下图:

Java final/finally/finalize与四种引用全解析

四、高频面试题标准答案

以下为面试中常见问题的标准回答,可直接背诵掌握。

4.1 final、finally、finalize 有何区别?

  1. final 是关键字,用于定义不可变性(类、方法、变量)。
  2. finally 是异常处理结构中的代码块,保证无论如何都会执行,常用于资源释放。
  3. finalize 是Object类中的方法,在GC回收对象前被调用,目前已废弃。

4.2 四种引用分别是什么?

强引用、软引用、弱引用、虚引用。记忆口诀:强软弱虚,回收力度依次增强。

4.3 ThreadLocal 为何使用弱引用?

为防止内存泄漏。ThreadLocalMap的key采用弱引用,当外部对ThreadLocal对象的强引用置为null后,key在下一次GC时会被自动回收,避免Entry长期占用内存导致泄漏。

结束语

final、finally、finalize以及对象的四种引用类型,既是Java的基础知识,也是JVM内存管理的核心内容。深入理解这些概念,有助于编写更健壮的代码,减少潜在问题,并在面试中展现扎实的技术功底。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章