面试题:Java中的引用类型有哪几种?特点是什么?

发布时间 2024-01-12 17:38:04作者: 咬到舌头的小蛇

Java中引用类型及特点

  • 强 引用: 最普通的引用 Object o = new Object()
  • 软 引用: 垃圾回收器, 内存不够的时候回收 (缓存)
  • 弱 引用: 垃圾回收器看见就会回收 (防止内存泄漏)
  • 虚 引用: 垃圾回收器看见二话不说就回收,跟没有一样 (管理堆外内存) DirectByteBuffer -> 应用到NIO Netty

finalize(): 当对象被回收时, finalize()方法会被调用, 但是不推荐使用去回收一些资源,因为不知道他什么时候会被调用, 有时候不一定会调用

public class C {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize");
    }
}

强引用

正常引用,但没有人指向的时候就会被回收

import java.io.IOException;
/**
 * 强引用
 */
public class R1_NormalReference {
    public static void main(String[] args) throws IOException {
        //正常引用
        C c = new C();
        c = null;//没人指向
        System.gc();//DisableExplicitGC

        //阻塞一下,方便看结果
        System.in.read();
    }
}

软引用

垃圾回收器, 内存不够的时候回收 (缓存)

import java.io.IOException;
import java.lang.ref.SoftReference;

/**
 * 软引用
 */
public class R2_SoftReference {
    public static void main(String[] args) {
        SoftReference<byte[]> soft = new SoftReference<>(new byte[1024 * 1024 * 10]);//10M
        System.out.println(soft.get());
        //gc回收
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(soft.get());

        //再分配一个数组,好heap(堆)放不下, 这个时候系统会回收一次, 如果不够,会把软引用回收
        byte[] bytes = new byte[1024 * 1024 * 15];
        System.out.println(soft.get());

    }
}

结果:
[B@1540e19d
[B@1540e19d
null

前提设置 -Xmx30M 堆内存最大30M 用于测试

idea里这样设置

弱引用

遇到GC就会被回收

import java.lang.ref.WeakReference;
/**
 * 弱引用
 */
public class R3_WeakReference {
    public static void main(String[] args) {
        WeakReference<C> weak = new WeakReference<>(new C());
        System.out.println(weak.get());
        //gc回收
        System.gc();
        //遇到GC就会被回收
        System.out.println(weak.get());

    }
}

结果:
com.cz.reference.C@3c679bde
null
finalize

虚引用

不管三七二十一 遇到直接回收

/**
 * 虚引用
 */
public class R4_PhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue QUEUE = new ReferenceQueue();

    public static void main(String[] args) {

        PhantomReference<C> phantomReference = new PhantomReference<>(new C(),QUEUE);

        new Thread(() -> {
            while (true){
                LIST.add(new byte[1024*1024]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        new Thread(() -> {
            while (true){
                Reference<? extends C> poll = QUEUE.poll();
                if (poll != null){
                    System.out.println("-----虚引用对象被JVm回收了--------" + poll);
                    return;
                }
            }
        }).start();
    }
}
结果:
null
null
finalize
null
null

总结: 强软弱虚引用

  1. 强引用:正常的引用
  2. 软引用:内存不够, 进行清除,
  3. 弱引用:遇到GC就会被回收
    • 缓存, 没有容器引用指向的时候就需要清除缓存
    • ThreadLocal
    • WeakReferenceMap
  4. 虚引用:看见就回收, 且看不到值