Java的引用类型分析

引用的概念

  1. 引用可以描述为变量和具体对象之间的关联关系

    //Object类型的变量obj引用了一个Object类型的对象
    Object obj = new Object();
    //String类型的变量str引用了一个String类型的对象
    String str = new String("xxx");
    
    //引用关系建立之后 就可以通过变量操作对象了
    
  2. java中的引用类型

    • 强引用
    • 软引用
    • 弱引用
    • 虚引用

    引用强度是:强引用>软引用>弱引用>虚引用

    这几种引用关系扩展了对象只有“被引用”和“未引用”两种引用关系。

强引用

  1. 普通的代码中的引用关系就是强引用

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

    一个对象只要还存在一个强引用与之关联,任何情况下都不会被GC回收。

    如果在内存不足的情况下继续创建对象,JVM宁可抛出OOM(OutOfMemory)异常,也不会回收强引用对象。

    可以手动断开这种强引用关系

    obj = null;
    str = null;
    //此时new Object() 和 new String("xxx")对象没有了强引用关系
    //将会在适当的时机被GC回收
    

软引用

  1. 特点

    • 软引用用来描述一些有用但不是必需的对象的引用关系。
    • java中使用java.lang.ref.SoftReference类来表示软引用关系
    • 软引用关联的对象只有在内存不足时才会被GC回收。这个特点可以用来解决OOM问题。
    • 可以使用软引用来实现本地缓存:如文件缓存,图片缓存等。
  2. 代码实现

    //创建一个软引用对象
    SoftReference<String> softReference = new SoftReference<>(new String("softReference Test"));
    //调用GC
    System.gc();
    
    //内存充足时 会打印字符串
    //当内存不足时 会打印null
    System.out.println(softReference.get());
    

弱引用

  1. 特点

    • 弱引用也是用来描述非必需对象的
    • java中使用java.lang.ref.WeakReference类来表示
    • 弱引用关联的对象在GC调用时都会被回收,不论当前内存是否充足。
  2. 代码实现

    //创建一个弱引用对象
    WeakReference<String> weakReference = new WeakReference<>(new String("weakReference Test"));
    
    //打印字符串
    System.out.println(weakReference.get());
    
    //调用GC
    System.gc();
    
    //打印null
    System.out.println(weakReference.get());
    

虚引用

  1. 特点

    • 虚引用不会影响对象的生命周期,即跟没引用对象一样

    • 在java中用java.lang.ref.PhantomReference类表示

    • 虚引用关联的对象随时会被回收

    • 虚引用只能和一个关联队列一起使用

    • 查看PhantomReference类源码

      public class PhantomReference<T> extends Reference<T> {
      	//get方法直接返回null
          public T get() {
              return null;
          }
      
          //构造方法必须传一个ReferenceQueue 对象
          public PhantomReference(T referent, ReferenceQueue<? super T> q) {
              super(referent, q);
          }
      }
      
  2. 代码实现

    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    
    //创建一个虚引用对象
    PhantomReference<String> phantomReference = new PhantomReference<>(new String("PhantomReference Test"),referenceQueue);
    
    
    //打印null
    System.out.println(phantomReference.get());
    
    //调用GC
    System.gc();
    
    //打印null
    System.out.println(phantomReference.get());
    

ReferenceQueue的使用

  1. 软引用、弱引用、虚引用可以关联一个ReferenceQueue对象使用

  2. 当上面几种引用关系的对象被GC回收时,就会把相应的包装类放入到ReferenceQueue。

    比如下面代码

    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    //创建一个弱引用对象
    WeakReference<String> weakReference = new WeakReference<>(new String("PhantomReference Test"),referenceQueue);
    
    //当new String("PhantomReference Test")这个对象被回收时
    //weakReference这个对象会放入到referenceQueue中
    
    
  3. 可以从ReferenceQueue中取出相应的对象信息,做一些对象被回收后的处理。

  4. 模拟ReferenceQueue的使用。以WeakReference类型为列。SoftReference和PhantomReference一样。

    在主线程中创建多个WeakReference关联的对象,并调用GC。在一个守护线程中查看被回收对象的封装对象的信息

    static ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            int cnt = 1;
            while (true){
                try {
                    Reference reference = referenceQueue.remove();
                    System.out.println("第"+ (cnt++) +"此循环,"+reference+":被回收!!!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                //等待10毫秒
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //设置线程为守护线程 主线程结束后该线程自动结束
        thread.setDaemon(true);
        thread.start();
    
        //创建WeakReference引用对象 并调用GC回收
        for(int i = 0;i< 100;i++){
            WeakReference<String> weakReference = new WeakReference<>(new String("txx"),referenceQueue);
            System.gc();
        }
    
        //等待10秒 让后台线程执行完毕
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值