我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解Java的引用类型及使用场景

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解Java的引用类型及使用场景

每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱,今天这篇文章就简单介绍一下这四种类型,并简单说一下他们的使用场景。

1. 强引用(Strong Reference)

强引用类型,是我们最常讲的一个类型,我们先看一个例子:


package cn.bridgeli.demo.reference;
 

public class User {
 
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
 
}
 
package cn.bridgeli.demo.reference;
 
import org.junit.Test;
 

public class StrongReferenceTest {
 
    @Test
    public void testStrongReference() {
        User user = new User();
        user = null;
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们都知道当一个实例对象具有强引用时,垃圾回收器不会回收该对象,当内存不足时,宁愿 OOM,也就是抛出 OutOfMemeryError 异常也不会回收强引用的对象,因为 JVM 认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。但是当对象被赋值为 null 之后,会被回收,并且会执行对象的 finalize 函数,此时我们可以通过该函数拯救自己,但是有两点需要注意一个是只能拯救一次,当再次被垃圾回收的时候就不能拯救了,另一个就是有事没事千万不要重写次函数,本例只是为了说明问题重写了此函数,如果在工作中误重写了此函数,可能会导致垃圾不能回收,最终 OOM,另外有熟悉 GC 的同学没?猜一下我为什么要 sleep 一下?

2. 软引用(Soft Reference)

在我刚学 Java 的时候,并不知道怎么使用软引用,那时候只知道强引用,其实是通过 java.lang.ref.SoftReference 类来使用软引用的,为了说明软引用,我们先看一个例子:


package cn.bridgeli.demo.reference;
 
import org.junit.Test;
 
import java.lang.ref.SoftReference;
 

public class SoftReferenceTest {
 
    @Test
    public void testSoftReference() {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println(softReference.get());
 
        System.gc();
 
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        System.out.println(softReference.get());
 
        byte[] bytes = new byte[1024 * 1024 * 12];
 
        System.out.println(softReference.get());
    }
}

除了通过 get 方法获取我们的软引用对象之外,运行结果和强引用类型并没有什么区别是吧?结果和我们想的一样,但是别着急,加一个启动参数再试试:


-Xms20m -Xmx20m

我们都知道,这两个参数是控制 JVM 启动的时候堆的最大值和最小值的,这里面我们设置的最大值和最小值都是 20M,按照强引用的逻辑,我们一共申请了 22M 的空间,应该 OOM 才对,事实证明并没有,通过打印语句证明,我们的软引用被回收了,所以软引用的特点是:在内存足够的时候,软引用对象不会被垃圾回收器回收,只有在内存不足时,垃圾回收器则会回收软引用对象,当然回收了软引用对象之后仍然没有足够的内存,这时同样会抛出内存溢出异常。

看了软引用的特点,我们很容易想到软引用的使用场景:缓存。记得刚工作的时候,有个同事给我说,他做 Android,有一个加载图片的应用,特麻烦,会 OOM,其实使用软引用应该很轻松的能解决这个问题。

3. 弱引用(Weak Reference)

弱引用是通过 java.lang.ref.WeakReference 类来实现的,同样我们也先看一个例子:


package cn.bridgeli.demo.reference;
 
import org.junit.Test;
 
import java.lang.ref.WeakReference;
 

public class WeakReferenceTest {
 
    @Test
    public void testWeakReference() {
        WeakReference<User> weakReference = new WeakReference<>(new User());
        System.out.println(weakReference.get());
 
        System.gc();
 
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        System.out.println(weakReference.get());
    }
}

通过例子我们可以看到,弱引用是一种比软引用更弱的引用类型:在系统 GC 时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收。看到这里可能会有同学有疑问,GC 什么时候启动,除了我们显示调用外,我们并不能控制(其实就算我们显示调用,GC 也可能不会立即执行),而且 GC 之后,弱引用立即被回收,引用不到了,那么这个类型有什么用呢?其实这个类型还真有大用,我们鼎鼎大名的 ThreadLocal 类就是借助于这个类实现的,所以当你使用 ThreadLocal 的时候,就已经在使用弱类型了,我之前曾经写过关于 ThreadLocal 的文章,但是当时理解不是很准确,不过说明的例子是没有问题的,所以还有一定的参考价值,后面看看啥时候有机会重写一篇关于 ThreadLocal 的文章,详细说说这个类。

另外除了 ThreadLocal 类外还有一个类值得说一下,那就是 java.util.WeakHashMap 类,见名知意,我们就可以猜到这个类的特点。同样通过一个例子说明一下:


package cn.bridgeli.demo.reference;
 
import org.junit.Test;
 
import java.util.Map;
import java.util.WeakHashMap;
 

public class WeakHashMapTest {
 
    @Test
    public void testWeakHashMap() {
        Map map = new WeakHashMap<String, Object>();
        for (int i = 0; i < 10000; i++) {
            map.put("key" + i, new byte[i]);
        }
 
//        Map map = new HashMap<String, Object>();
//        for (int i = 0; i < 10000; i++) {
//            map.put("key" + i, new byte[i]);
//        }
    }
}

记得启动的时候设置一下,设置一下启动的时候堆的大小,不要设置太大,可以看出区别。

4. 虚引用(Phantom Reference)

通过前面的例子,我们可以看到引用强度是越来越弱的,所以虚引用是最弱的一种引用类型,到底有多弱呢,我们同样通过一个例子来看,需要说明的是,虚引用是通过 java.lang.ref.PhantomReference 类实现的。


package cn.bridgeli.demo.reference;
 
import org.junit.Test;
 
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.List;
 

public class PhantomReferenceTest {
 
    ReferenceQueue referenceQueue = new ReferenceQueue();
    List<Object> list = new ArrayList<>();
 
    @Test
    public void testPhantomReference() {
        PhantomReference<Object> phantomReference = new PhantomReference<>(new Object(), referenceQueue);
        System.out.println(phantomReference.get());
 
        new Thread(() -> {
            while (true) {
                Reference reference = referenceQueue.poll();
                if (null != reference) {
                    System.out.println("============ " + reference.hashCode() + " ============");
                }
            }
        }).start();
 
        new Thread(() -> {
            while (true) {
                list.add(new byte[1024 * 1024 * 10]);
            }
        }).start();
 
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们看到了是什么?虽然软引用和弱引用也很弱,但是我们还是可以通过 get 方法获取到我们的引用对象,但是虚引用却不行,点进去看一下源码,我们可以看到虚引用的 get 方法,直接返回 null,也就是我们直接拿不到虚引用对象,那么这个类型又有什么使用场景呢?其实这个类型就不是给我们普通程序员使用的,在 io、堆外内存中有使用,所以对于我们普通程序员来说,了解到存在这个类型,另外通过上面的例子,我们还可以看到:当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。那么我们就可以在程序中发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些必要的行动。

以上就是详解Java的引用类型及使用场景的详细内容,更多关于Java 引用类型及使用场景的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

详解Java的引用类型及使用场景

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java的引用类型及使用场景是什么

这篇文章将为大家详细讲解有关Java的引用类型及使用场景是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java
2023-06-14

Oracle数据类型详解及应用场景

Oracle数据类型详解及应用场景Oracle数据库作为一款领先的关系型数据库管理系统,在数据存储方面提供了多种不同的数据类型,以满足不同数据的需求。本文将介绍Oracle数据库中常用的数据类型,以及它们的应用场景,并提供具体的代码示例。
Oracle数据类型详解及应用场景
2024-03-07

C#中的引用类型以及特殊引用类型详解

本文详细讲解了C#中的引用类型以及特殊引用类型,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-11-13

Redis多种数据类型以及使用场景

SDS简单动态字符串struct sdshdr {// 记录buf数组中已使用字节的数量// 等于SDS所保存字符串的长度int len;// 记录buf数组中未使用字节的数量int free;// 字节数组,用于保存字符串char buf[];}free表示
Redis多种数据类型以及使用场景
2014-11-22

详解Java中$符的各种使用场景

在Java编程中,我们会经常看到$符的身影,比如经常在配置文件中看到$符号作为变量占位符,用于在运行时动态地获取变量值。本文将详细介绍$符号在Java编程中的各种应用场景,以帮助您更好地理解和运用这个符号,感兴趣的小伙伴可以收藏一下
2023-05-17

redis的五种数据类型及使用场景有哪些

redis 支持五种数据类型:字符串、列表、哈希表、有序集合和无序集合。这些类型分别适合存储各种数据场景,例如文本数据、有序元素列表、映射键值数据、按分数排序的元素集合以及独特的元素集合。Redis 五种数据类型及使用场景Redis 是一
redis的五种数据类型及使用场景有哪些
2024-04-08

redis的五种数据类型及使用场景是什么

redis 提供了五种数据类型,分别为:字符串:存储文本、json 数据、缓存、计数器;哈希:存储用户数据、会话信息、对象属性;列表:存储队列、时间线、排名、购物车;集合:存储标签、分类、关注列表、黑名单;有序集合:存储排行榜、投票、优先级
redis的五种数据类型及使用场景是什么
2024-04-08

Redis 中ZSET数据类型命令使用及对应场景总结(案例详解)

目录1.zadd添加元素2.zrem 从有序集合key中删除元素3.zscore 返回有序集合key中元素member的分值4.zincrby 为有序集合key中元素增加分值5.zcard获取有序集合key中元素总个数6.zrange 正序
2023-01-03

Redis 中ZSET数据类型命令使用及对应场景总结(案例详解)

这篇文章主要介绍了Redis 中ZSET数据类型命令使用及对应场景总结,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-01-03

Mysql中的find_in_set() 函数用法详解及使用场景

一、find_in_set() 函数详解 示例: select FIND_IN_SET('1', '1,2,3');// 结果:1select FIND_IN_SET('3', '1,2,3');// 结果:3select FIND_IN_
2023-08-20

Kotlin与Java泛型缺陷和应用场景详解

这篇文章主要为大家介绍了Kotlin与Java泛型缺陷和应用场景详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-21

深入理解Java中Filter的作用种类及应用场景

Filter(过滤器)是JavaWeb中的一种重要组件,可以对请求和响应进行拦截处理,对数据进行过滤和处理。Filter可以实现许多功能,如:鉴权、日志记录、字符编码转换、数据压缩、请求重定向等等
2023-05-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录