Java中的四种引用类型

Java中的四种引用类型,分别是强引用、软引用、弱引用、虚引用。

强引用:

我们平时最常使用的引用就是强引用。
例如 Object o=new Object();
这里的 o 就是一个强引用。我们知道java是有垃圾回收机制的,只要对象还被强引用指向,那么这个对象就还不会被回收,但是如果强引用不指向这个对象了,GC就会回收该对象。

做个实验来验证一下:
public class A {
    private String name;

    A(String name) {
        this.name = name;
    }
	/*当对象被回收时会调用这个方法,我们打印一句话,来看对象是否被回收*/
    @Override
    protected void finalize() throws Throwable {
        System.out.println(name+"被回收了");
    }
}

public class One {
    public static void main(String[] args) {
        A a=new A("jj");
        A a1=new A("zh");
        a=null;//我们让a不在指向"jj"这个对象。
        System.gc();
        System.in.read();
    }
}

执行结果

软引用:

软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。

下面以一个例子来进一步说明强引用和软引用的区别:
在运行下面的Java代码之前,需要先配置参数 -Xms2M -Xmx3M,将 JVM 的初始内存设为2M,最大可用内存为 3M。
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        byte[] buff = new byte[1024 * 1024*3];
    }

如果我们申请的内存空间超出了设置的值,由于强引用对象不会自动回收,所以会报错堆内存溢出。
在这里插入图片描述

下面来看看这个例子:

这里我们一共也申请了102410243的内存,但是用于其中两份是软引用对象,当内存空间不足时,这部分对象就会被回收。

public class Two {
    public static void main(String[] args) throws InterruptedException {
        SoftReference<byte[]> softReference=new SoftReference<>(new byte[1024 * 1024*2]);
        System.out.println(softReference.get());//这个时候还是可以得到的byte的
        System.gc();
        Thread.sleep(500);
        System.out.println(softReference.get());
        byte[] bytes = new byte[1024 * 1024 * 1];
        System.out.println(softReference.get());
    }
}

执行结果

弱引用:

弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。
我们以与软引用同样的方式来测试一下弱引用:

public class Three {
    public static void main(String[] args) {
        WeakReference<byte[]> sr = new WeakReference<>(new byte[1024 * 1024*2]);
        System.gc(); //主动通知垃圾回收
        System.out.println(sr.get());
    }
}

运行结果就是null。

虚引用:

虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。

public class PhantomReference<T> extends Reference<T> {
    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

那么传入它的构造方法中的 ReferenceQueue 又是如何使用的呢?

引用队列(ReferenceQueue)

引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。

与软引用、弱引用不同,虚引用必须和引用队列一起使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值