WeakHashMap是种弱引用的HashMap,这是说,WeakHashMap里的key值如果没有外部强引用,在垃圾回收之后,WeakHashMap的对应内容也会被移除掉。

1.1 Java的引用类型

在讲解WeakHashMap之前,我们需要了解Java中引用的相关类:

ReferenceQueue,引用队列,与某个引用类绑定,当引用死亡后,会进入这个队列。

HardReference,强引用,任何以类似String str=new String()建立起来的引用,都是强引用。在str指向另一个对象或者null之前,该String对象都不会被GC(Garbage Collector垃圾回收器)回收;

WeakReference,弱引用,可以通过java.lang.ref.WeakReference来建立,当GC要求回收对象时,它不会阻止对象被回收,该对象会立刻被回收;

SoftReference,软引用,可以通过java.lang.ref.SoftReference来建立,和弱引用一样,当GC要求回收时,它不会阻止对象被回收,但不同的是该对回收过程会被延迟,必须要等到JVM heap内存不够用,接近产生OutOfMemory错误时,才会回收;

PhantomReference,虚引用,可以通过java.lang.ref.PhantomPeference来建立,这种类型的引用很特别,大多数时间,无法通过它拿到其引用的对象,但是,当这个对象死亡的时候,该引用还是会进入ReferenceQueue队列。

下面提供一个例子来分别说明它们的作用:

ReferenceQueue<Ref> queue = new ReferenceQueue<Ref>();

// 创建一个弱引用

WeakReference<Ref> weak = new WeakReference<Ref>(new Ref("Weak"),queue);

// 创建一个虚引用

PhantomReference<Ref> phantom = new PhantomReference<Ref>(new Ref(

"Phantom"), queue);

// 创建一个软引用

SoftReference<Ref> soft = new SoftReference<Ref>(new Ref("Soft"),queue);

System.out.println("引用内容:");

System.out.println(weak.get());

System.out.println(phantom.get());

System.out.println(soft.get());

System.out.println("被回收的引用:");

for (Reference r = null; (r = queue.poll()) != null;) {

System.out.println(r);

}

Ref这个类是个自定义的测试类,源码如下所示:

class Ref {

Object v;

Ref(Object v) {

this.v = v;

}

public String toString() {

return this.v.toString();

}

}

在这个例子里,分别创建了弱引用、虚引用和软引用,get()方法用于获取它们引用的Ref对象,可以注意到,Ref对象在外部并没有任何引用,所以,在某个时间点,GC应当会回收对象。来看看代码执行的结果:

引用内容:

Weak

null

Soft

被回收的引用:

可以看到,弱引用和软引用的对象还是可达的,但是虚引用是不可达的。被回收的引用没有内容,说明GC还没有回收它们。

这证实了虚引用的性质

虚引用非常弱,以至于它自己也找不到自己的引用内容。

对之前的代码进行改造,在输出内容前加入代码:

// 强制垃圾回收

System.gc();

再执行一次,得到结果:

引用内容:

null

null

Soft

被回收的引用:

java.lang.ref.WeakReference@3b764bce

java.lang.ref.PhantomReference@759ebb3d

现在可达的引用只剩下Soft了,引用队列里多出了两条引用,说明WeakReference和PhantomReference的对象被回收。

再修改一次代码,让WeakPeference和PhantomReference去引用一个强引用对象:

Ref wr = new Ref("Hard");

WeakReference<Ref> weak = new WeakReference<Ref>(wr, queue);

PhantomReference<Ref> phantom = new PhantomReference<Ref>(wr, queue);

输出结果如下所示:

引用内容:

Hard

null

Soft

被回收的引用:

这证实了弱引用的性质

弱引用的对象,如果没有被强引用,在垃圾回收后,引用对象会不可达。

1.2 WeakHashMap实现方式

WeakHashMap利用了ReferenceQueue和WeakReference来实现它的核心功能:当key值没有强引用的时候,从WeakHashMap里移除。

先来看看WeakHashMap的键值对实体类WeakHashMap.Entry的实现:

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {

Entry(Object key, V value,

ReferenceQueue<Object> queue,

int hash, Entry<K,V> next) {

super(key, queue);

this.value = value;

this.hash  = hash;

this.next  = next;

}

...

}

关键注意两处:

1、Entry继承自WeakReference;

2、Entry本身没有保存key值,而是把key作为WeakReference的引用对象交给了super构造。

这说明,Entry是个针对key值的弱引用。

WeakHashMap实现清除陈旧实体的方法是expungStaleEntries(),其源码实现如下:

private void expungeStaleEntries() {

//遍历引用队列,找到每一个被GC收集的对象

for (Object x; (x = queue.poll()) != null; ) {

synchronized (queue) {

@SuppressWarnings("unchecked")

Entry<K,V> e = (Entry<K,V>) x;

int i = indexFor(e.hash, table.length);

//从链表里移除该实体

Entry<K,V> prev = table[i];

Entry<K,V> p = prev;

while (p != null) {

Entry<K,V> next = p.next;

if (p == e) {

if (prev == e)

table[i] = next;

else

prev.next = next;

//帮助GC执行

e.value = null;

size--;

break;

}

prev = p;

p = next;

}

}

}

}

expungStaleEntries()方法会在resize、put、get、forEach方法里被调用。

WeakHashMap和Java引用类型详细解析的更多相关文章

  1. java容器详细解析

    前言:在java开发中我们肯定会大量的使用集合,在这里我将总结常见的集合类,每个集合类的优点和缺点,以便我们能更好的使用集合.下面我用一幅图来表示 其中淡绿色的表示接口,红色的表示我们经常使用的类. ...

  2. java容器详细解析(转)

    :在java开发中我们肯定会大量的使用集合,在这里我将总结常见的集合类,每个集合类的优点和缺点,以便我们能更好的使用集合.下面我用一幅图来表示 其中淡绿色的表示接口,红色的表示我们经常使用的类. 1: ...

  3. Java正则表达式详细解析

    元字符 正则表达式使用一些特定的元字符来检索.匹配和替换符合规则的字符串 元字符:普通字符.标准字符.限定字符(量词).定位字符(边界字符) 正则表达式引擎 正则表达式是一个用正则符号写出来的公式 程 ...

  4. java类生命周期详细解析

    (一)详解java类的生命周期 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前 ...

  5. 转:二十一、详细解析Java中抽象类和接口的区别

    转:二十一.详细解析Java中抽象类和接口的区别 http://blog.csdn.net/liujun13579/article/details/7737670 在Java语言中, abstract ...

  6. 2019年 Java 面试题解析

    2019年 Java 面试题解析 转载地址:https://www.cnblogs.com/Zz-maker/p/11193930.html 作者: Zz_maker 包含的模块: 本文分为十九个模块 ...

  7. java jar包解析:打包文件,引入文件

    java jar包解析:打包文件,引入文件 cmd下: jar命令:package包打包 javac命令:普通类文件打包 Hello.java: package org.lxh.demo; publi ...

  8. springmvc 项目完整示例06 日志–log4j 参数详细解析 log4j如何配置

    Log4j由三个重要的组件构成: 日志信息的优先级 日志信息的输出目的地 日志信息的输出格式 日志信息的优先级从高到低有ERROR.WARN. INFO.DEBUG,分别用来指定这条日志信息的重要程度 ...

  9. Java构造和解析Json数据的两种方法详解二

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...

随机推荐

  1. ssh登录nat模式的VMware虚拟机

    有时候本地PC是固定IP上网方式且无多余IP,而我们又希望使用putty登陆VMware中的虚拟机且虚拟机可以上外网,那么这时候就可以使用端口映射. 1.本地环境简述 本地PC IP:192.168. ...

  2. VS2010 自定义向导

    最近在学OpenGL,不想使用OpenGL的GLUT工具,自己写了一个初始化OpenGL的类,并在win32中使用,每次都要新建一个win32项目,然后将OpenGL初始化类拷贝到项目,然后进行各种初 ...

  3. haxe 配置

    安装所有类库: 命令提示符 haxelib install 类库名 如:haxelib install openfl 配置安卓: 命令提示符 haxelib run openfl setup andr ...

  4. Java 多态,重载,重写

    1.多态(polymorphism): 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象, ...

  5. android webview处理下载内容

    url = "http://m.mumayi.com/"; WebView = (WebView) findViewById(R.id.webView1); WebView.get ...

  6. jsp导入外部样式

    在博客园遇到一位朋友,她将我的代码下载下去,运行的时候,jsp页面的样式不存在,不会显示出来. 这里就将我之前写的SpringSpringmvcMybatis做一些修改. jdk1.8 加入了两个ja ...

  7. UVALive 4992 Jungle Outpost(半平面交)

    题意:给你n个塔(点)形成一个顺时针的凸包,敌人可以摧毁任何塔,摧毁后剩下的塔再组成凸包 在开始的凸包内选一点为主塔,保证敌人摧毁尽量多塔时主塔都还在现在的凸包内,求出最多摧毁的塔 题解:这题关键就是 ...

  8. C#中:函数访问级别对函数形参访问级别的约束

    Inconsistent accessibility: parameter type 'Program.CommandLineInfo' is less accessible than method ...

  9. 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上)【转载】

    转自: DBAplus社群 http://www.toutiao.com/m5762164771/ 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上) - 今日头条(TouTiao.com ...

  10. JSP标准标签库(JSTL)--SQL标签库 sql

    了解即可.SQL标签库 No. 功能分类 标签名称 描述 1 数据源标签 <sql:setDataSource> 设置要使用的数据源名称 2 数据库操作标签 <sql:query&g ...