先说结论:

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

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

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

那么弱引用是什么?

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

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

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

为什么需要弱引用?

先看一段代码:

 package cn.larry.weakref.pojo;

 public final class Product {
private String name; public Product() {
super();
} public Product(String name) {
super();
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Product [name=" + name + "]";
} }
 package cn.larry.weakref.test;

 import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap; import org.junit.Test; import cn.larry.weakref.pojo.Product; public class WrTest {
private Product product = new Product("iPhone"); @Test
public void strongRef() {
Map<Product, Integer> map = new HashMap<>();
map.put(product, 111); product = null;// 关键
map.keySet().forEach(System.out::println);// 对象仍然存在!
}
}

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

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

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

怎么使用弱引用?

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

     @Test
public void weakRef_1() { ReferenceQueue<Product> rq = new ReferenceQueue<>();
// WeakReference<Product> wr=new WeakReference<Product>(product);
WeakReference<Product> wr = new WeakReference<Product>(product, rq);// 引用队列
System.out.println("wr是否已被添加至引用队列:" + wr.isEnqueued()); Map<WeakReference<Product>, Integer> map = new HashMap<>();
map.put(wr, 111); product = null;// 关键
// System.gc();// 关键 map.keySet().forEach(e -> System.out.println(e.get()));// 不gc()的话,还能访问对象,否则null。
System.out.println("wr是否已被添加至引用队列:" + wr.isEnqueued());
}

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

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

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

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

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

更便捷的方法:

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

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

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

补充说明:

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

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

参考

理解Java中的弱引用(Weak Reference)
译文:理解Java中的弱引用
 

Java的四种引用类型之弱引用的更多相关文章

  1. java中四种引用类型(对象的强、软、弱和虚引用)

    对象的强.软.弱和虚引用在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2 ...

  2. java中四种引用类型

    java中四种引用类型  今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在 ...

  3. 你知道Java的四种引用类型吗

    关于java四种引用类型,我也是刚了解,特此记下! 在Java中提供了四个级别的引用:强引用,软引用,弱引用和虚引用.在这四个引用类型中,只有强引用FinalReference类是包内可见,其他三种引 ...

  4. java的四种引用类型

    java的引用分为四个等级:4种级别由高到低依次为:强引用.软引用.弱引用和虚引用. ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回 ...

  5. java中四种引用类型(转)

    今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在网上查资料,感觉收获颇多, ...

  6. Java中的四种引用类型,强引用,软引用,弱引用,虚引用

    对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用  2软引用  3弱引用 ...

  7. Java中四种引用:强、软、弱、虚引用

    这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...

  8. java基础之 数据类型 & 值传递 引用传递 & String & 四种引用类型

    一.Java数据类型 分为基本数据类型与引用数据类型 基本数据类型: byte:Java中最小的数据类型,在内存中占1个字节(8 bit),取值范围-128~127,默认值0 short:短整型,2个 ...

  9. Java魔法堂:四种引用类型、ReferenceQueue和WeakHashMap

    一.前言 JDK1.2以前只提供一种引用类型——强引用 Object obj = new Object(); .而JDK1.2后我们多另外的三个选择分别是软引用 java.lang.ref.SoftR ...

随机推荐

  1. Sublime Text 无法使用Package Control或插件安装失败的解决方法

    Sublime Text用了一年多了,公司搬家近期突然发现Package Control无法安装新插件了.尽管不影响原有功能的使用.还是要解决它.因为本人用Windows系统,仅仅讨论Windosw下 ...

  2. js cookie库

    顺手摘下来 /** * @desc 设置Cookie * @param {String} name * @param {String} value * @param {Number} expires ...

  3. django 创建数据库表 命令

    一旦你觉得你的模型可能有问题,运行 python manage.py validate . 它可以帮助你捕获一些常见的模型定义错误. 模型确认没问题了,运行下面的命令来生成 CREATE TABLE ...

  4. [Jobdu] 题目1391:顺时针打印矩阵

    题目描述: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2 ...

  5. Scala之集合Collection

    概述 Scala的集合类能够从三个维度进行切分: 可变与不可变集合(Immutable and mutable collections) 静态与延迟载入集合 (Eager and delayed ev ...

  6. [na]出口选路pbr小实验视频

    什么是策略路由? 一般都是部署在出口路由器,用于路径强制分发的, 优先级高于路由表. 策略路由小实验视频 这个是读书时候录的一个策略路由小实验

  7. UnityTestTools測试工具

    由于工作关系,要了解Unity上的測试工具,该工具基于Nunit框架.通过查阅资料了解到在Unity5.3中做出了一些改变,自带的仅仅剩下单元測试工具,假设想用其它的工具比方断言.集成測试,就须要前往 ...

  8. CCNotificationCenter(一)

    const std::string testsName[MAX_COUNT] = { "Bug-350", "Bug-422", "Bug-458&q ...

  9. nginx检查报错 error while loading shared libraries: libprofiler.so.0: cannot open shared object file: No such file or directory

    在centos7.3上编译安装nginx-1.12.2 启动测试出错 [root@web02 local]# /usr/local/nginx/sbin/nginx -t /usr/local/ngi ...

  10. 李洪强iOS开发之-sql数据库的使用

    一,创建工程 二: 导入头文件 三:导入 四: 数据库增删改查 //因为是结构体类型,所以用assign //1.创建数据库(保存路径) @property(nonatomic,assign)sqli ...