• Java的四种引用类型之弱引用


    先说结论:

    首先,Java中有四种引用类型:强引用、软引用、弱引用、虚引用。-- 在 Java 1.2 中添加的,见 package java.lang.ref;

    其次,这几个概念是与垃圾回收有关的。

    然后,如果你不知道这几个概念,那你用的肯定都是强引用。例如 String str = new String(); 这个 strnew String() 的引用类型就是强引用。

    那么弱引用是什么?

    弱引用,就是引用与对象之间的联系很弱,弱到垃圾回收器会无视这个引用,直接回收对象。

    软引用与弱引用类似,但只在内存不足时才会被回收。

    虚引用最差,甚至不能通过 get() 获取到对象。

    为什么需要弱引用?

    先看一段代码:

     1 package cn.larry.weakref.pojo;
     2 
     3 public final class Product {
     4     private String name;
     5     
     6     public Product() {
     7         super();
     8     }
     9 
    10     public Product(String name) {
    11         super();
    12         this.name = name;
    13     }
    14 
    15     public String getName() {
    16         return name;
    17     }
    18 
    19     public void setName(String name) {
    20         this.name = name;
    21     }
    22 
    23     @Override
    24     public String toString() {
    25         return "Product [name=" + name + "]";
    26     }
    27     
    28 }
    View Code
     1 package cn.larry.weakref.test;
     2 
     3 import java.lang.ref.ReferenceQueue;
     4 import java.lang.ref.WeakReference;
     5 import java.util.HashMap;
     6 import java.util.Map;
     7 import java.util.WeakHashMap;
     8 
     9 import org.junit.Test;
    10 
    11 import cn.larry.weakref.pojo.Product;
    12 
    13 public class WrTest {
    14     private Product product = new Product("iPhone");
    15 
    16     @Test
    17     public void strongRef() {
    18         Map<Product, Integer> map = new HashMap<>();
    19         map.put(product, 111);
    20 
    21         product = null;// 关键
    22         map.keySet().forEach(System.out::println);// 对象仍然存在!
    23     }
    24 }

    在上面的代码中,虽然在第21行已经将 product引用置空(null),但是第22行的代码仍然可以访问到该引用最初指向的对象!

    这时,如果map中有多个Key,Product类又不可修改(不能添加识别字段),那你怎么确定并删除这个Key,能否自动移除该Key?弱引用就可以满足这样的要求。

    一个经典的场景就是缓存,特别是缓存图片(加载到内存中),此时缓存肯定会包含一个指向内存中图片缓存的引用。问题在于,如果使用强引用,你必须决定何时不再需要该缓存并手动移除它。

    怎么使用弱引用?

    代码如下(与上面的测试代码在同一个 WrTest 类中):

     1     @Test
     2     public void weakRef_1() {
     3 
     4         ReferenceQueue<Product> rq = new ReferenceQueue<>();
     5         // WeakReference<Product> wr=new WeakReference<Product>(product);
     6         WeakReference<Product> wr = new WeakReference<Product>(product, rq);// 引用队列
     7         System.out.println("wr是否已被添加至引用队列:" + wr.isEnqueued());
     8 
     9         Map<WeakReference<Product>, Integer> map = new HashMap<>();
    10         map.put(wr, 111);
    11 
    12         product = null;// 关键
    13 //        System.gc();// 关键
    14 
    15         map.keySet().forEach(e -> System.out.println(e.get()));// 不gc()的话,还能访问对象,否则null。
    16         System.out.println("wr是否已被添加至引用队列:" + wr.isEnqueued());
    17     }

    上面第4行构造了一个引用队列。

    第5或6行构造了一个弱引用,区别在于是否指定引用队列。

    如果指定了弱引用的引用队列,垃圾回收器会在回收对象之后将该弱引用添加至引用队列中 -- 可以在回收之后通过弱引用的 isEnqueued() 方法来判断。

    需要注意:①必须将原强引用置空(第12行),且不能有其他强引用指向该对象;②必须主动调用垃圾回收器(第13行)。然后就能看到弱引用指向的对象已经不存在了(第15行) -- 弱引用本身还存在,所以map不为空。

    但是,这时已经可以手动删除这个Key了。

    更便捷的方法:

    JDK提供了 WeakHashMap 可以更加方便的完成上面的工作,代码如下:

     1     @Test
     2     public void weakRef_2() {
     3         WeakHashMap<Product, Integer> map = new WeakHashMap<>();
     4         map.put(product, 111);
     5 
     6         product = null;// 关键
     7         // System.gc();//关键
     8 
     9         map.keySet().forEach(System.out::println);// 不gc()的话,还能访问对象,否则null。
    10 
    11     }

    这种情况下,map.size()是0,即该Key自动被移除!!!

     

    补充说明:

    1、虽然可以主动调用垃圾回收器,但垃圾回收器并不总是会执行的。

    2、Product类参考了 理解Java中的弱引用(Weak Reference) 中的pojo类。

    参考

    理解Java中的弱引用(Weak Reference)
    译文:理解Java中的弱引用
     
  • 相关阅读:
    京东采集器100元、求安慰(京东产品、评价(好评、中评、差评)、价格(参考价、京东价)、图片(大图、小图)、图片识别、广告语)
    Oracle数据库创建表ID字段的自动递增
    iv
    oracle 无监听,无法用ip连接问题(ORA12541: TNS无监听程序错误 )
    sql exp
    dockManager1、dockpanl使用笔记
    windows常用控件
    ComboBoxEdit数据绑定
    winform窗体传值
    分组匹配的一个示例
  • 原文地址:https://www.cnblogs.com/larryzeal/p/5831619.html
Copyright © 2020-2023  润新知