【JVM】面试题-Java中有哪些引用类型


Java中有哪些引用类型

1、强引用

Java中默认声明的就是强引用,比如:

复制代码
Object obj = new Object();
obj = null;

只要强引用存在,垃圾回收器将永远不会回收被引用的对象。

如果想被回收,可以将对象置为null

复制代码
======= 🌟 青柠来相伴,代码更简单。🌟 =======
📚 本文所有内容,我都整理在了 青柠合集 里。👇
🎯 搜索关注【青柠代码录】,即可查看所有合集文章 ~
======= 🌟 =================== 🌟 =======

最传统的"引用"的定义,是指在程序代码之中普遍存在的引用赋值,即类似"0bject obj=new object()"这种引用关系。

无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。

复制代码
public class StrongRefDemo {
    public static void main(String[] args) {
        // 默认就是强引用
        Object obj = new Object();

        // 只要强引用还在,GC 绝不回收
        System.gc();
        System.out.println("GC后对象还在:" + obj);

        // 断开强引用,对象无引用指向,可被GC回收
        obj = null;

        System.gc();
        System.out.println("置null后:" + obj); // null
    }
}

2、软引用(SoftReference)

在内存足够的时候,软引用不会被回收,只有在内存不足时,系统才会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会跑出内存溢出异常。

复制代码
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);

在系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出内存溢出异常。

复制代码
import java.lang.ref.SoftReference;

public class SoftRefDemo {
    public static void main(String[] args) {
        // 创建大对象
        byte[] data = new byte[1024 * 1024 * 10];
        
        // 包装为软引用
        SoftReference<byte[]> softRef = new SoftReference<>(data);

        // 断开强引用
        data = null;

        // 内存充足时,能拿到对象
        System.out.println("内存充足,获取对象:" + softRef.get());

        // 若内存爆满触发GC,软引用对象会被回收,get() 返回 null
    }
}

3、弱引用(WeakReference)

进行垃圾回收时,弱引用就会被回收。

被弱引用关联的对象,只能生存到下一次垃圾收集之前。当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被弱引用关联的对象。

复制代码
import java.lang.ref.WeakReference;

public class WeakRefDemo {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        // 包装弱引用
        WeakReference<Object> weakRef = new WeakReference<>(obj);

        // 断开强引用
        obj = null;

        // 触发GC
        System.gc();
        Thread.sleep(200);

        // GC之后,弱引用对象直接被回收,get() = null
        System.out.println("GC后弱引用获取:" + weakRef.get()); // null
    }
}

4、虚引用(PhantomReference)

一个对象是否有虛引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用,来获得一个对象的实例。为一个对象设置虛引用关联的,唯一目的,就是能在这个对象被收集器回收时,收到一个系统通知(回收跟踪)。

无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时,返回一个通知。

复制代码
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomRefDemo {
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        Object obj = new Object();

        // 虚引用必须配合引用队列才有意义
        PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);

        // 断开强引用
        obj = null;

        System.gc();
        Thread.sleep(200);

        // 虚引用永远拿不到对象,get() 一定是 null
        System.out.println("虚引用get:" + phantomRef.get()); // null

        // 回收后虚引用会进入队列,用来做善后清理
        System.out.println("队列是否收到通知:" + queue.poll());
    }
}

5、引用队列(ReferenceQueue)

引用队列可以与软引用、弱引用、虚引用一起配合使用。

当垃圾回收器准备回收一个对象时,如果发现它还有引用,就会在回收对象之前,把这个引用加入到引用队列中。

程序可以通过判断引用队列中,是否加入了引用,来判断被引用的对象,是否将要被垃圾回收,这样可以在对象被回收之前,采取一些必要的措施。

示例:弱引用 + 引用队列

复制代码
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class RefQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        // 1. 创建引用队列
        ReferenceQueue<Object> queue = new ReferenceQueue<>();

        // 2. 普通对象 + 弱引用绑定队列
        Object obj = new Object();
        WeakReference<Object> weakRef = new WeakReference<>(obj, queue);

        // 3. 断开强引用
        obj = null;

        // GC 回收时,引用都会自动进队列
        System.gc();
        Thread.sleep(200);

        // 4. 从队列取出引用,说明对象即将被回收
        WeakReference<?> pollRef = (WeakReference<?>) queue.poll();
        if (pollRef != null) {
            System.out.println("收到回收通知,对象准备被GC回收,可做资源清理");
        }
    }
}

补充:软引用 / 虚引用 ,绑定队列套路完全一样

相关推荐
计算机安禾1 小时前
【c++面向对象编程】第7篇:static成员:属于类而不是对象的变量和函数
java·c++·算法
cms小程序插件【官方】1 小时前
pbootcms版AI自动发文插件升级到3.0版本,支持多组关键词
jvm·人工智能
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题 第47题】【JVM篇】第7题:Young GC 和 Full GC 分别采用什么算法?
java·jvm·后端·算法·面试
lyp90h2 小时前
Claude Code CLI System Prompt 完整分析
java·前端·prompt
xu_ws2 小时前
redis的io多路复用和Java NIO的区别
java·redis·nio
Hesionberger2 小时前
LeetCode98:验证二叉搜索树(多解)
java·开发语言·python·算法·leetcode·职场和发展
千寻girling2 小时前
周日那天参加的力扣周赛... —— 10号
java·javascript·c++·python·算法·leetcode·职场和发展
凛_Lin~~2 小时前
lifecycle源码解析 (版本2.5.1)
android·java·安卓·lifecycle
青柠代码录2 小时前
【JVM】面试题-Parallel 回收器
jvm