一文弄清Java的四大引用及其两大传递

news2024/9/21 4:29:49

开场白

Hello大家好呀,我是CodeCodeBond
最近在复习很多很多的基础知识,有了很多新的感悟~


在这里插入图片描述
话不多说,直接发车✈


四大引用

问题切入点

在学习 Thread线程利用ThreadLocalMap实现线程的本地内存(变量副本)的时候,是基于ThreadLocal为Key,Object为Value的一个Entry。并且,这个Entry键值对的键是使用了一个弱引用,且说道这样会存在一个内存泄漏的问题。
在这里插入图片描述
那么为什么会内存泄露呢?这个弱引用是什么呢?又有哪些引用呢?他们之间有什么区别呢?

怀揣着一堆问题,我开始了学习— 🐻

其实引用类型的选择也是垃圾回收、是否可达的策略选择!

所以我们从垃圾回收和可达性这两个方面去理解Java的四种引用类型!

Java有哪四种类型的引用?

可达性分析是JVM中垃圾回收的垃圾判断算法,通过从GC Root出发->遍历引用链判断对象是否可达判断对象是否进行垃圾回收,具体GC Root是什么,垃圾回收算法是什么就不多赘述了。

强引用

定义: 强引用是最常用最常见的引用,我们正常使用没有特别处理的都是强引用的场景。

特点

  • 只要有一个对象是强引用指向它,就不会被垃圾回收。
  • 在可达性分析中,从GC Roots开始的引用链上,只要有强引用链条存在,目标对象就被视为可达。

软引用

定义: 软引用通过SoftReference类来实现,允许垃圾回收器在内存不足时回收这些对象。

特点

  • 软引用对象在内存充足时不会被回收,但在内存不足时可能会被回收。
  • 在可达性分析中,软引用对象不被立即视为可达,只有在内存充足的情况下,软引用对象才被保留。

弱引用

定义:弱引用通过WeakReference类来实现,允许垃圾回收器在下一次垃圾回收时回收这些对象。

影响

  • 弱引用对象在下一次GC时大概率会被回收,不论内存是否充足。
  • 在可达性分析中,弱引用对象不会被视为可达,即使对象有弱引用,仍然会被回收。

虚引用

定义:虚引用通过PhantomReference类来实现,主要用于跟踪对象的回收状态。(像一次性用品)

影响

  • 虚引用对象本身并不会影响对象的生命周期,它们总是在GC时被回收。
  • 在可达性分析中,虚引用对象从未被视为可达。它们主要用于管理系统资源的回收和清理。

回归问题

回到问题的开始,为什么ThreadLocalMap会存在内存泄漏的问题呢?主要原因就是因为身为Key的ThreadLocal是一个弱引用的存在,它在没有外部强引用的前提下,很可能被直接垃圾回收掉,但是Value是一个Object的强引用,导致Key被gc了,但是Value还在。也就是我们说的内存泄露的问题了。

ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()get()remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后最好手动调用remove()方法,预防一下。

两大传递

两大传递一般指的是值传递引用传递

但是,在Java中是不存在引用传递的,Java所有的传递都是值传递

我们一起来简单证明一下:

基本数据类型

引用数据类型 试验1

public class Test {
    public static void main(String[] args) {
        String s1 = "CodeCodeBond";
        modifyString(s1);
        System.out.println(s1);
    }

    public static void modifyString(String s){
        s = "GGBond!";
    }
}
//打印结果不变
//CodeCodeBond

这是一个最简单的String引用类型,可以看到修改后打印结果不变,这个例子可以说明String是值传递的,方法的形参并没有影响原来的实参。

引用数据类型 试验2

注意看!!

public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        System.out.println("init:" + list);
        modify(list);
        System.out.println("modify later:" + list);
    }

    public static void modify(ArrayList<String> list){
        list.add("CodeCodeBond");
    }
}

在这里插入图片描述
我们可以看到实参集合居然被修改了,不是说是值传递吗?为什么实参被修改了?

原来,Java对于对象引用类型,传递的是引用的副本(内存地址值)。通过这个引用副本可以修改原始对象的内容。

思考题 Question

但是我们看回试验1的String引用类型为什么不能修改实参呢?

可以思考一下这个问题~文末Answer我们再来解答这个问题(点击目录快速跳转)

引用数据类型 试验3

为了进一步证明Java中确实只有值传递,我们来进行试验3

public class Test {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("CodeCodeBond");
        System.out.println("init:" + list);
        modify(list);
        System.out.println("modify later:" + list);
    }

    public static void modify(ArrayList<String> list){
        list = new ArrayList<>();
        list.add("GGBond");
    }
}

打印结果如图:
在这里插入图片描述
看吧,在方法中我们重新将引用副本指向一个新的地址,但是实参并没有被改变,也就强力的说明了传递的是一个引用副本,有力证明了Java中确实只存在值传递这一说!


最后的最后

思考题 Answer

为什么试验1中,String类值传递引用副本值的时候,无法修改原来实参呢?因为在方法中修改的时候是通过直接赋值的操作来修改,而String是一个final class不可变类,所以String机制是新建一个String对象去存储"CodeCodeBond"字符串的,所以并不能修改实参,你想到了吗?😄

我是CodeCodeBond,我的座右铭是

比上次好,比下次差。

我们下次见! 8.3 1:25
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1972795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简单的docker学习 第1章 docker 概述

Docker 学习笔记 本文是b站动力节点docker学习视频的笔记整理&#xff0c;主要用于自己学习复习使用&#xff0c;视频具体地址为 : 动力节点docker 第一章 docker 概述 1.1 课程引人入 1.1.1 开发/运维互掐 ​ 开发与测试和运维间的矛盾&#xff0c;主要是由于环境的不同而…

flutter 做代码混淆

第一种、手动混淆 修改代码中出现次数多的 类目 方法 。修改静态资源的名字&#xff0c;转静态资源为webp 第二种、使用flutter 自带的命令行工具进行混淆 混淆 Dart 代码 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 使用pragma(vm:entry-point) 装饰器修改方…

【界面开发实战】使用DevEco Studio编写支付宝首页

效果展示 知识点 层叠布局 上一篇文章已经介绍了&#xff0c;这篇文章中不再赘述&#xff0c;如果想了解的话可以去看上一篇文章&#xff0c;链接如下&#xff1a; http://t.csdnimg.cn/CnBZMhttp://t.csdnimg.cn/CnBZM 弹性布局 作用&#xff1a;提供更加有效的方式对容器…

YOLOV5 改进:替换backbone为MobileVIT

1. 介绍 yolov5替换主干网络的步骤如下,依旧和之前的一样 2. 更改common文件 将下面代码加入common最下面即可: from einops import rearrange import torch import torch.nn as nn# Transformer Attention模块定义 class TAttention(nn.Module):def __init__(self, dim, …

string的底层简单实现(造轮子)

文件&#xff1a;String.h ----- 头文件 String.cpp ----- 源文件 Test.cpp ----- 源文件 实现细节&#xff1a; 实现带参构造&#xff1a; 在实现带参构造建议不使用初始化列表&#xff0c;初始化去写不太好&#xff1a; :_str(new char[strlen(str)1]) 用初始化列表要在…

如何在 Jupyter Notebook 中直接设置全局随机种子的方法及易错地方、notebook和pycharm中设置随机种子的区别

结论&#xff1a; 在 Jupyter Notebook 中直接设置全局随机种子的方法是确保每个单独的代码块中都调用相同的 set_seed 函数。这是最简单且有效的方法。在每个代码块开头设置随机种子&#xff0c;确保代码在每次执行时具有相同的随机数生成顺序。 易错地方&#xff1a; …

mac配置git的sshkey

在MAC中配置Git的SSH Key&#xff1a; 1.打开终端 2.生成SSH密钥&#xff0c;输入以下命令&#xff1a; ssh-keygen -t rsa -b 4096 -C “你自己的账号电子邮件地址” 按回车键后&#xff0c;系统会提示你输入文件保存路径&#xff0c;默认为~/.ssh/id_rsa直接按回车键使用默…

数据结构初阶之排序(上)

排序的概念及其应用 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使⼀串记录&#xff0c;按照其中的某个或某些关键字的⼤⼩&#xff0c;递增或递减的排列起来的操作。 排序的应用 如下图&#xff1a; 样例数组 下面我们给出一组乱序的数组&#xff0c;接下来的算…

程序员进阶架构知识体系、开发运维工具使用、Java体系知识扩展、前后端分离流程详解、设计模式开发实例汇总专栏分享

场景 作为一名开发者&#xff0c;势必经历过从入门到自学、从基础到进阶、从学习到强化的过程。 当经历过几年企业级开发的磨炼&#xff0c;再回头看之前的开发过程、成长阶段发现确实是走了好多的弯路。 作为一名终身学习的信奉者&#xff0c;秉承持续学习、持续优化的信念…

GitHub推出全新AI模型平台:简化开发者体验

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

《计算机网络》(第8版)第8章 互联网上的音频/视频服务 复习笔记

第 8 章 互联网上的音频/视频服务 一、概述 1 多媒体信息的特点 多媒体信息&#xff08;包括声音和图像信息&#xff09;最主要的两个特点如下&#xff1a; &#xff08;1&#xff09;多媒体信息的信息量往往很大&#xff1b; &#xff08;2&#xff09;在传输多媒体数据时&a…

【网络】TCP协议——TCP连接相关、TCP连接状态相关、TCP数据传输与控制相关、TCP数据处理和异常、基于TCP应用层协议

文章目录 Linux网络1. TCP协议1.1 TCP连接相关1.1.1 TCP协议段格式1.1.2 确定应答(ACK)机制1.1.3 超时重传机制 1.2 TCP连接状态相关1.2.1 TIME_WAIT状态1.2.2 CLOSE_WAIT 状态 1.3 TCP数据传输与控制相关1.3.1 滑动窗口1.3.2 流量控制1.3.3 拥塞控制1.3.4 延迟应答1.3.5 捎带应…

草的渲染理论

Unity引擎提供了基础的terrain工具&#xff0c;可以制作地形&#xff0c;在上面刷树刷草。对于树&#xff0c;Unity是支持带LOD的Prefab&#xff0c;不同距离显示不同细节的模型&#xff0c;效果还不错。对于草&#xff0c;Unity支持两种方式来刷草&#xff0c;一种是Add Grass…

汇凯金业:解读区块链概念、类型与独特优势

区块链作为一种具有革命性的创新技术&#xff0c;正在逐渐改变我们的生活和商业模式。它的去中心化、安全可靠、不可篡改等特性&#xff0c;为解决许多传统领域中的问题提供了新的思路和方法。 一、区块链的基本概念 区块链是一种具有创新性的计算机技术应用模式&#xff0c;…

C#复习之类和对象

知识点一&#xff1a;什么是类 基本概念&#xff1a; 具有相同特征 具有相同行为 一类事物的抽象 类是对象的模板 可以通过类创建出对象 类的关键字 Class 知识点二&#xff1a;类声明在哪里 类一般声明在namespace语句块中 知识点三&#xff1a;类声明的语法 知识点四&#xf…

html+css 实现文字滚动的按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

2024年前端趋势:全栈或许是不容错过的选择!

近年来&#xff0c;前端开发的技术不断推陈出新&#xff0c;2024年也不例外。在这个变化迅速的领域&#xff0c;全栈开发逐渐成为一股不容忽视的趋势。无论你是经验丰富的开发者&#xff0c;还是刚刚入门的新手&#xff0c;掌握全栈技术都能让你在竞争中脱颖而出。而在这个过程…

Spring -- 拦截器

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 文章目录 1. 自定义拦截器2. 注册配置拦截器3. 拦截器详解3.1 拦截路径3.2 拦截器执行流程 3.3 DispatcherServlet源码分析3.3.1 初始化:3.3.2 处理请求3.3.3 适配器 拦截器是Spring框架提供的…