美团一面:说一说Java中的四种引用类型?

这篇具有很好参考价值的文章主要介绍了美团一面:说一说Java中的四种引用类型?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型,称为Reference。并且当时Java中的对象只有两种状态:被引用和未被引用。当一个对象被引用时,它将一直存在于内存中,直到它不再被任何引用指向时,才会被垃圾回收器回收。而被引用也就是强引用。

而在JDK1.2之后对引用的概念进行了扩充,分为了强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference),这4种引用的强度依次减弱。他们的关系如下如:

强引用

强引用是Java中最常见的引用类型。当你创建一个对象并将其赋值给一个变量时,这个变量会持有该对象的强引用。

Order order = new Order(); // 只要order还指向Order对象,那么Order对象就不会被回收
order = null; // 强引用都被设置为 null 时,不可达,则Order对象被回收

只要存在强引用指向对象,垃圾回收器将永远不会回收该对象,即使内存不足也不会回收。这可能导致内存溢出,因为即使内存不足,JVM也不会回收强引用对象。当强引用都被设置为null时,对象变成不可达状态,垃圾回收器会在适当的时候将其回收。

比如以下示例,我们创建一个2M的数组,但是我们设置JVM参数:-Xms2M -Xmx3M,将JVM的初始内存设为2M,最大可用内存为3M。

public static void main(String[] args) {  
    //定义一个2M的数组  
    byte[] objects = new byte[1024 * 1024 * 2];  
}

此时我们执行方法后,发现报错:


对于强引用,即使内存不够使用,直接报错OOM,强引用也不会被回收。

对于强引用,就好比生活中,当我们拥有家里的钥匙时,我们可以随时进入你的家,即使我们不需要进入,也能确保我们可以进入。钥匙是我们进入家的强引用。只有当我们不再拥有钥匙时,我们才无法进入家,类似于当没有强引用指向一个对象时,该对象才能被垃圾回收。

软引用

在JDK1.2之后,用java.lang.ref.SoftReference类来表示软引用。软引用允许对象在内存不足时被垃圾回收器回收。如果一个对象只有软引用指向它,当系统内存不足时,垃圾回收器会尝试回收这些对象来释放内存,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。软引用适用于需要缓存大量对象,但又希望在内存不足时释放部分对象以避免内存溢出的情况,用于实现缓存时,当内存紧张时,可以释放部分缓存对象以保证系统的稳定性。

以下示例我们设置JVM参数为:-Xms3M -Xmx5M,然后连续创建了10个大小为1M的字节数组,并赋值给了软引用,然后循环遍历将这些对象打印出来。

private static final List<Object> list = Lists.newArrayList();  
  
public static void main(String[] args) {  
    IntStream.range(0, 10).forEach(i -> {  
        byte[] buff = new byte[1024 * 1024];  
        SoftReference<byte[]> sr = new SoftReference<>(buff);  
        list.add(sr);  
    });  
  
    System.gc(); // 主动通知垃圾回收  
  
    list.forEach(l -> {  
        Object obj = ((SoftReference<?>) l).get();  
        System.out.println("Object: " + obj);  
    });  
}

然后我们执行代码之后:


对于打印结果中,只有最后一个对象保留了下来,其他的obj全都被置空回收了。即说明了在内存不足的情况下,软引用将会被自动回收。

对于弱引用,就像我们医药箱里的备用药,当我们需要药品时,我们会先看看医药箱里是否有备用药。如果医药箱里有足够的药品(内存足够),我们就可以使用备用药;但如果医药箱里的备用药不够了(内存不足),我们可能会去药店购买。在内存不足时,垃圾回收器可能会回收软引用对象,类似于我们在医药箱里的备用药被用完时去药店购买。

弱引用

JDK1.2之后,用java.lang.ref.WeakReference来表示弱引用。弱引用与软引用类似,但强度更弱。即使内存足够,只要没有强引用指向一个对象,垃圾回收器就可以随时回收该对象。弱引用适用于需要临时引用对象的场景,如临时缓存或临时存储对象。也可以用于解决对象之间的循环引用问题,避免内存泄漏。

对于上述示例中,我们将数组赋值给弱引用

private static final List<Object> list = Lists.newArrayList();  
  
public static void main(String[] args) {  
    IntStream.range(0, 10).forEach(i -> {  
        byte[] buff = new byte[1024 * 1024];  
        WeakReference<byte[]> sr = new WeakReference<>(buff);  
        list.add(sr);  
    });  
  
    System.gc(); // 主动通知垃圾回收  
  
    list.forEach(l -> {  
        Object obj = ((WeakReference<?>) l).get();  
        System.out.println("Object: " + obj);  
    });  
}

执行结果发现所有的对象都是null,即都被回收了。

对于弱引用,就像我们正在旅行,使用一张一次性地图。我们只在需要导航时使用地图,一旦旅行结束,我们就不再需要地图了。这时我们可以选择扔掉地图,类似于弱引用,在垃圾回收器运行时,无论内存是否充足,对象都可能被回收。

虚引用

在 JDK1.2之后,用java.lang.ref.PhantomReference类来表示虚引用。虚引用是最弱的引用类型,它几乎对对象没有任何影响,不能通过虚引用获取对象,也不能通过它来阻止对象被垃圾回收。从源码中可以看出它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。

虚引用可以用于在对象被回收时进行后续操作,如对象资源释放或日志记录,常用于跟踪对象被垃圾回收的状态,执行一些清理工作。

而对于弱引用,就像我们去商店,商店入口处的门闩并不直接影响你进入房屋,但它会在有人进入或离开时发出声音,提醒你有人进店(欢迎光临)或者离开(欢迎再来)。类似地,虚引用并不直接影响对象的生命周期,但它可以在对象被回收时发出通知,让你有机会进行一些后续操作,比如资源释放或者记录日志。

引用队列

引用队列(ReferenceQueue)是Java中的一个特殊队列,用于配合软引用、弱引用和虚引用,实现更灵活的对象引用和回收管理。

引用队列的主要作用是跟踪对象的垃圾回收过程。当一个软引用、弱引用或虚引用指向的对象被垃圾回收器回收时,如果它们与一个引用队列关联,那么这些引用就会被自动加入到引用队列中。通过监视引用队列中的对象,我们可以了解到对象的回收状态,从而执行一些额外的操作,比如资源释放或日志记录等。

总结

Java中的四种引用类型各具特点,可根据程序需求选择合适的引用类型。强引用保证对象不被意外回收,软引用和弱引用用于实现缓存或解决内存敏感问题,而虚引用则用于对象回收后的通知和清理操作。合理使用引用类型可以更好地管理内存和避免内存泄漏问题。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等文章来源地址https://www.toymoban.com/news/detail-842312.html

到了这里,关于美团一面:说一说Java中的四种引用类型?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 说一说ajax的请求过程?

    AJAX(Asynchronous JavaScript and XML)是一种通过在后台与服务器进行异步通信的技术,用于实现页面的局部更新和动态加载数据。下面是 AJAX 请求的一般过程: 1:创建 XMLHttpRequest 对象:在 JavaScript 中,使用 new XMLHttpRequest() 创建一个新的 XMLHttpRequest 对象,用于发送和接收数据。

    2024年02月08日
    浏览(44)
  • 面试官:说一说Zookeeper中Leader选举机制

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,可以微信搜索【小奇JAVA面试】第一时间阅读,回复【资料】更有我为大家准备的福利哟! 今天又是

    2023年04月08日
    浏览(48)
  • React进阶 - 11( 说一说 PropTypes 和 DefaultProps )

    本章内容 截止到上一节的内容,我们使用了一个 TodoList 的案例,大概了解了 React 的一些入门知识。从本节内容开始,我们将进入 React 进阶知识的学习 在组件拆分时,我们知道每个组件都有自己的 props ,这个参数是从父组件那里接收的一些数据。 那么有个疑问,子组件在接

    2024年01月24日
    浏览(35)
  • 面试官:说一说 Spring 与 SpringBoot 的区别?

    Spring 为开发 Java 应用程序提供了全面的基础架构支持,它将 Java 对象交由容器统一管理,从而实现控制反转(IOC)和依赖注入(DI),并提供了一些常用模块如 SpringAOP、SpringJDBC、SpringMVC 等等 SpringBoot 继承了 Spring 的核心思想,并进一步简化应用开发 Spring 和 SpringBoot 的区别主

    2024年03月25日
    浏览(41)
  • 有一说一,这个云计算认证证书真的值得一考!

    疯狂的裁员!股价降低!在美国,一股寒冷的创业寒流正在席卷而来。不只是硅谷进入了冬天,国内的传统互联网寒潮也凛冽地来了。在传统 IT体系结构逐渐式微、产业规模不断缩小的情况下,许多 IT工程师都面临着下岗、跳槽等问题。 IT从业人员如何实现技术转型?IT新人

    2024年02月03日
    浏览(57)
  • 面试官:说一说mysql的varchar字段最大长度?

    在mysql建表sql里,我们经常会有定义 字符串 类型的需求。 比方说user表里的名字,就是个字符串。mysql里有两个 类型 比较适合这个场景。 char和varchar。 声明它们都需要在字段边上加个数组,比如 char(100) 和 varchar(100) ,这个100是指当前字段能放的 最大字符数 。 char和varchar的

    2023年04月16日
    浏览(39)
  • 2023-06-17:说一说redis中渐进式rehash?

    2023-06-17:说一说redis中渐进式rehash? 答案2023-06-17: 在Redis中,如果哈希表的数组一直保持不变,就会增加哈希冲突的可能性,从而降低检索效率。为了解决这个问题,Redis会对数组进行扩容,通常是将数组大小扩大为原来的两倍。然而,这个扩容过程会引起元素在哈希桶中的

    2024年02月09日
    浏览(43)
  • 记录--说一说css的font-size: 0

    平常我们说的 font-size:0 ;就是设置字体大小为0对吧,但是它的用处不仅仅如此哦,它还可以消除子行内元素间额外多余的空白! 是否出现过当多个img标签平铺的时候,会出现几个像素的间距?就像这样👇(为了醒目加了个红色的框框) 大家都知道img是行内元素,比如当我

    2024年02月14日
    浏览(42)
  • 【C++】C++ 引用详解 ⑨ ( 常量引用初始化 | C / C++ 常量分配内存的四种情况 )

    使用 \\\" 普通变量 \\\" 初始化 \\\" 常量引用 \\\" , 就是将 普通变量 赋值给 常量应用 , 也可以理解为 将 变量转为常量 ; 下面的代码 , 就是上述 使用 普通变量 初始化 常量引用 : 在 博客 【C++】C 语言 和 C++ 语言中 const 分析 ( const 左数右指原则 | C 语言中常量的原理和缺陷

    2024年02月10日
    浏览(43)
  • React - 请你说一说setState是同步的还是异步的

    难度级别:中高级及以上                               提问概率:70%  在React项目中,使用setState可以更新状态数据,而不能直接使用为this.state赋值的方式。而为了避免重复更新state数据,React首先将state添加到状态队列中,此时我们可以通过shouldComponentUpdate这

    2024年04月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包