Java高级技术第二章——Java的四种引用类型,强引用,若引用,虚引用,软引用详解..

前言

前言点击此处查看:
http://blog.csdn.net/wang7807564/article/details/79113195

Java的引用

Java的引用机制有四种,强引用,弱引用,软引用和虚引用。
Java对比Cpp的一个典型的特征就是避免了手动去管理内存,不用自己去写析构函数。这在很大程度上降低了语言的难用程度,降低了内存泄漏和OOM情况的发生的概率。
但是,由于JVM回收对象的方式对程序员来讲是透明的,如果想要手动去调控某些对象的声明周期,可能不太容易操作。自从JAVA2之后,Java就将引用细分为上述四种,一方面可以方便程序员去控制对象的声明周期,另一方面,也可以方便JVM的垃圾回收。

强引用

强引用就是平时在编程中用到最多的一种引用方式,例如:

Object obj = new Object();
String str = "object";

这种引用方式,就是强引用。我们可以利用这种引用方式,为某一个变量赋值。
强引用的特点是直到程序终止运行之后,内存才会被回收。也就是说,当操作系统的内存不足时,就算JVM抛出OOM异常,提示内存空间不足,也不会回收这个强引用对象。
但是,如果我们改成如下代码:

Object obj = new Object();
obj = null;

那么obj对象将会被JVM回收掉,因为我们已经手动解除了obj变量到Object对象之间的引用关系。
那么,也就是说,强引用适合用在对程序运行起到至关重要之处,如果该对象不存在,程序就无法继续执行。

软引用

软引用定义的类是java.lang.ref.SoftReference,它的特点是:
只有当系统将要发生OOM时,JVM才会回收掉该对象。
也就是说,软引用可以应用在比较重要,但不是至关重要之处。例如各种缓存,就可以用软引用来实现,示例代码如下:

SoftReference<Object> soft = new SoftReference<Object>(new String("hello"));
System.out.println(soft.get());

在上面的代码中可以看到,如果soft变量没有被回收,会返回这个变量的实例,如果返回null,则代表该对象的实例已经被回收。

弱引用

弱引用使用java.lang.ref.WeakReference来表示,它的生存时间比软引用还要再短一些。它的内存回收特点是:
只要当JVM进行垃圾回收时,无论内存是否充足,都会被回收。
示例代码:

WeakReference<String> weak = new WeakReference<String>(new String("hello"));
System.out.println(weak.get());
System.gc();
System.out.println(weak.get());

返回结果第一次自然是”hello”,第二次会返回null.因为此时,JVM已经完成了对内存的垃圾回收,该变量weak会被回收。如果一个对象需要被偶尔使用到,可以考虑能否成为使用弱引用的场景。通过弱引用也可以实现对象的缓存,只不过这个缓存的声明周期更短。

虚引用

虚引用又成为幽灵引用,使用java.lang.ref.PhantomReference类来表示,可以类比为虚拟的引用,就如同没有建立引用关系一样。因为,在程序运行的任何时候,该引用随时都会被系统回收掉。也因为这一点,可以认为虚引用不影响Java对象的生命周期,在任何时候都无法通过虚引用来获取到对象的实例。
虚引用可以联合引用队列,来实现当发生内存垃圾回收的时候,起到通知的效果。

引用队列

当使用GC释放对象内存的时候,会将引用加入到引用队列,这相当于是一种通知机制。引用队列使用的类是ReferenceQueue.
当我们把一个引用与引用队列相关联之后,在将该对象的内存释放后,会将引用加入到引用队列中,这样,我们就可以自定义一些动作,用来对内存释放后作出一些响应。
利用这种响应,可以达到替代finalize()方法的作用。由于finalize()方法比较消耗系统资源,因此一般很多场合都不建议使用。而如果使用引用队列,就可以在对象被回收之后,来响应相关应答。
如果是监控对象是否被销毁,那么最适合使用虚引用,如sun.misc.Cleaner就是使用虚引用,达到监控对象销毁的目的,在NIO中就是利用这样的方式来实现的。
注册一个引用到引用队列上的代码如下:

    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<String>  queue = new ReferenceQueue<>();
        WeakReference<String> pr = new WeakReference<>(new String("hello"),queue);
        //不使用new String()无法被回收.
        System.out.println("into while:");
        System.gc();
        while (true){
            Reference<? extends String> str =  queue.remove(); //阻塞,直到获取到
            if(str != null){
                System.out.println(str.get()); //返回结果是null,实际只起到了通知作用.
                break;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值