Java中引用的概念

序言:

Java对于引用概念经历过两个时期,JDK1.2之前和JDK1.2之后。在JDK1.2以前Java对于引用的定义很传统,如果reference类型的数据中存储的数值指定是另外一块内存的起始地址,就称为这块内存代表着一个引用.这个定义过于狭隘,在整个应用中对象就存在两种状态存在引用或者不存在。这样会产生一定的问题,对于我们应用系统存在于一些对象只在初始化使用一次(却被其它对象引用),存在一些对象是不经常被调用(也被其它对象引用),也存在一些对象是一直在被使用的。当内存资源足够的情况下,不会发生太大问题,一旦出现内存中资源紧缺,我们需要释放一些对象内存。我们肯定是期望这些只在初始化使用一次和不经常被调用的对象的内存释放出来。但是因为被引用的对象是不会被垃圾回收器给回收掉的,所以终止就会导致系统因内存而直接崩溃,这种现象我将其类比于以前的大锅饭(不论干不干活都有饭吃)。

针对于上述JDK1.2的状况Java在JDK1.2之后对于引用的概念细致化分为4种(让我们可以针对不同情况使用不同引用),分别为强引用(Strong Reference),软引用(Soft Reference),弱引用(Weak Reference),虚引用 (Phantom Reference).4种引用强度依次降低。java对于这四种引用的具体实现在java.lang.ref包下,如图所示。

类所在包情况:

完整类图:

2.1:强引用(Strong Reference)

java中最普遍存在的引用类型.例如我们在Object obj = new Object()时就会产生的这样的引用。在java应用中只要上述情况的强引用存在,垃圾回收器永远不会回收被引用对象。

2.2:软引用(Soft Reference)

软引用:可引用一些有用但却不是应用必须的对象,对于这些对象在应用内存资源不足(垃圾回收器已经进行过一次回收了),要发生内存溢出之前,垃圾回收器将这些对象列为可回收对象范围之内再进行第二次回收,如果此次回收内存资源还是不足,那么就会发生内存溢出溢出。在java中使用SoftReference类来实现软引用。

2.3:弱引用(Weak Reference)

弱引用和软引用的功能一样也是用以引用非必须的对象。但是它的强度比软引用更弱,不论jvm中内存是否充足,垃圾回收器在下一次垃圾回收的时候这些被弱引用的对象肯定会被回收。在java中使用WeakReference类来实现弱引用。

2.4:虚引用(Phantom Reference)

虚引用在四种引用类型中最弱的一种引用关系,它的存在对于对象的生存时间没有丝毫影响,也无法通过虚引用来获取一个对象的实例。它实际的作用是在当该对象被垃圾回收是可触发系统通知。在java中使用PhantomReference来实现虚引用。

2.5:引用队列 ReferenceQueue

通过查看SoftReference,WeakReference,PhantomReference三种不同类可以看到在初始化方法中都有ReferenceQueue的的影子,ReferenceQueue在其中充当的角色是用以实现在被三种引用对象被gc时,其它线程可以通过ReferenceQueue可以进行感知并作出一些处理。(后续有代码测试 )

3:代码应用:

3.1:强引用

/**
 *强引用测试 为测试效果使用-Xmx10m -Xms10m
 */
public class StrongReferenceTest {

    //堆内
    public  static List<Byte[]> datas = new ArrayList<>();

    public static void main(String[] args) throws Exception {

        for (int i=0;i<10;i++ ) {
            datas.add(new Byte[1024*1024]);
            Thread.sleep(100);
            //触发gc
            System.gc();
        }

    }
}

运行结果:

3.2:软引用测试

/**
 * 软引用测试 设置内存大小为10m -Xmx10m -Xms10m
 * @author fangyuan
 */
public class SoftReferenceTest {

    public  static List<SoftReference<Byte[]>> datas = new ArrayList<>();

    public static void main(String[] args) throws Exception {

        for (int i=0;i<5;i++ ) {
            SoftReference<Byte[]> srf = new SoftReference<Byte[]>(new Byte[1024*512]);
            datas.add(srf);
        }
        //验证数据是不是被gc掉
        for (SoftReference softReference:datas) {
            System.out.println(softReference.get());
        }

    }
}

运行结果:

从上述结果可以看到:当jvm感觉内存不足时(内存不足的定义是什么?与堆内存大小以及该引用对象get的时间都有关系),垃圾回收器会回收软引用对象。

3.3 弱引用测试

/**
 * 弱引用测试  这里不设置最大内存大小
 * @author fangyuan
 */
public class WeakReferenceTest {

    public  static List<WeakReference<Byte[]>> datas = new ArrayList<>();

    public static void main(String[] args) throws Exception {

        for (int i=0;i<5;i++ ) {
            WeakReference<Byte[]> weakReference = new WeakReference<Byte[]>(new Byte[1024*512]);
            datas.add(weakReference);
        }

        //验证数据
        for (WeakReference weakReference:datas) {
            System.out.print(weakReference.get());
        }

        System.out.println();

        //触发gc
        System.gc();

        Thread.sleep(1000);

        //验证数据是不是被gc掉
        for (WeakReference weakReference:datas) {
            System.out.print(weakReference.get());
        }

    }
}

结果:

测试结果发现,弱引用对象只能存活到下一次垃圾回收器开始工作之前,无关于现有系统内存大小。

3.4 虚引用

//源码
public class PhantomReference<T> extends Reference<T> {

    //虚引用无法通过get方法获取对应实例对象
    public T get() {
        return null;
    }

    //初始化 配合ReferenceQueue做到被引用对象被gc之后能过通知用户线程 进行额外处理
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

测试代码当gc虚引用时,用户线程得知并作出处理:

/**
 * 测试ReferenceQueue 与PhantomReference 不设置内存最大值
 * @author fangyuan
 */
public class PhantomReferenceTest {

    public  static List<PhantomReference<Byte[]>> datas = new ArrayList<>();

    public  static ReferenceQueue<Byte[]> referenceQueues = new ReferenceQueue<>();

    public static void main(String[] args) throws Exception {

        //设置
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                int count =0 ;
                while(true){
                    try {

                        Reference<? extends Byte[]> pr;
                        if ((pr = referenceQueues.remove()) !=null){
                            System.out.println("第"+(count++)+"个回收了对象"+pr);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        });

        thread.setDaemon(true);
        thread.start();

        while (true) {
            PhantomReference<Byte[]> phantomReference = new PhantomReference<Byte[]>(new Byte[1024*1024],referenceQueues);
            datas.add(phantomReference);
        }

    }
}

测试结果:

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、 面向对象的基本特征。 1.抽象: 抽象就是忽略一个主题与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 2.继承: 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 3.封装: 封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性: 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势, 2、 Java的基本数据类型都有什么?String是基本数据类型吗? 基本数据类型包括int、short、byte、double、boolean、char、long、float String不是基本数据类型,是引用数据类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值