先说结论:

首先,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. docker lnmp php

    使用 Docker 构建 LNMP 环境 https://segmentfault.com/a/1190000008833012 Docker 快速上手指南 https://segmentfault. ...

  2. 创建Hive/hbase相关联的表异常

    hive> CREATE TABLE hperson(id string, name string,email string) STORED BY 'org.apache.hadoop.hive ...

  3. php批量删除数据库下指定前缀的表

    如何用php批量删除数据库下所有前缀为prefix_的表. 例子,统一删除前缀为“prefix_”的表. <?php //设置数据库连接信息.数据库服务器地址,数据库用户名,数据密码 mysql ...

  4. js控制表单操作的常用代码小结

    收集了一些在WEB前台开发中常用的一些控制表单操作函数. 1.鼠标经过时自动选择文本鼠标划过自动选中:<input type="text" value="默认值&q ...

  5. [sql]MySQL数据备份小结

    一 MySQL备份恢复总结: 1,备份所有库 2,分库备份 3,备份某库中的某表 4,备份某库中的多个表 5,分表备份 6,只备份表结构 7,只备份数据 二 MySQL备份恢复参数总结: -A 备份所 ...

  6. if else 的或(||)

    = "node01" ]; then ssh -p2222 root@.xx.xx.xxx else echo "hello world" #当$=='node ...

  7. Django视图之视图函数

    下面来说说常见的视图函数: HttpResponse() Http404() HttpResponseNotFound() 上面三个函数功能比较简单,用得少,就不多说了! render() rende ...

  8. Oracle PLSQL Demo - 27.Declare & Run Sample

    declare v_sal ) :; begin --if you could not see the output in console, you should set output on firs ...

  9. 【转帖】漫话C++0x(四) —- function, bind和lambda

    实在是觉得此文总是去翻感觉不太好.于是果断转过来了,想看原文的请戳:http://www.wuzesheng.com/?p=2032 本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lam ...

  10. windows党码农在linux下你最需要的软件列表TOP10

    NO 10.QQ 神奇的TX,经常更新接口,使得linux社区的模仿软件总是跟不上步伐,一整就不能登陆使用.可是老大,您怎么自从2009-01-04发布了第一版QQ for Linux 1.0 Bet ...