通过底层原理理解Java是值传递还是引用传递?

news2024/11/20 0:28:25

本文学习目标或者巩固的知识点

  • 参数传递方式
    • 值传递
    • 引用传递
    • 指针传递
  • 彻底理解Java的值传递和引用传递
    • 从底层的角度分析
    • 值传递会发生复制行为

Java的参数传递例子

快手的一面面试曾经问到过此类题目,所以记下此篇加深印象。
问:求下面main方法中的输出结果,如果知晓结果则可跳过此篇

public static void main(String[] args) {
    int num = 1;
    值传递_基本类型(num);
    System.out.printf("值传递_基本类型方法结束后=>num=%d \n", num);
    Person person = new Person();
    person.name = "张三";
    引用传递_引用类型(person);
    System.out.printf("引用传递_引用类型方法结束后=>person.name=%s \n", person.name);
}

public static void 值传递_基本类型(int num){
    num = 2;
}
public static void 引用传递_引用类型(Person person){
    person.name = "李四";
}

public static class Person{
    public String name;
}

输出

值传递_基本类型方法结束后=>num=1 
引用传递_引用类型方法结束后=>person.name=李四 

什么是值传递?

百度百科: 值传递是指在调用函数时将 实际参数 复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

Java中基本数据类型:整型(4种)、浮点型(2种)、字符型(1种)、布尔型(1种)。

在赋值操作符(=)的作用下,将变量的值从调用者的作用域传递到被调用的作用域。

对于基本数据类型,复制的是值本身,而不是变量的内存地址。因此,如果一个变量在调用过程中被修改,那么在返回调用者的作用域时,其值仍然是复制时的值。

public static void main(String[] args) {
    int num = 1;
    Integer number = 1;
    char ch = '1';
    Character character = '1';
    值传递_基本类型(num,number,ch,character);
    System.out.printf("值传递_基本类型方法结束后=>num=%d, number=%d, ch=%c, character=%c \n", num, number, ch, character);
}
public static void 值传递_基本类型(int num, Integer number, char ch, Character character){
    num = 2;
    number = 2;
    ch = '2';
    character = '2';
    System.out.printf("值传递_基本类型方法内=>num=%d, number=%d, ch=%c, character=%c \n", num, number, ch, character);
}

值传递_基本类型方法内=>num=2, number=2, ch=2, character=2 
值传递_基本类型方法结束后=>num=1, number=1, ch=1, character=1 

什么是引用传递?

百度百科:所谓 引用传递 是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

在Java中与引用传递相类似的有引用类型的传递(如数组、Object类),在赋值操作符(=)的作用下,将变量的引用指向的对象从调用者的作用域传递到被调用的作用域

对于引用类型,复制的是对象的引用,而不是对象本身。因此,如果一个对象在调用过程中被修改,那么在返回调用者的作用域时,所引用的对象仍然是调用时的对象,但其内容可能会发生变化。比如:如果一个对象包含其他对象作为成员,那么在值传递过程中,只有对象的引用会被复制,而成员对象则不会被复制。这意味着在调用过程中,如果修改了对象内部的成员对象,那么在返回调用者的作用域时,该成员对象可能已经不再是最新的。

值传递:引用数据类型

public static void main(String[] args) {
    int[] arr = new int[1];
    char[] chs = new char[1];
    List<Integer> ls = new ArrayList<>();
    Person person = new Person();
    
    arr[0] = 1;
    chs[0] = '1';
    ls.add(1);
    person.name = "张三";
    
    System.out.printf("引用传递_引用类型方法执行前=> " +
            "\n arr[0]=%d, chs[0]=%c,ls.get(0)=%d, person.name=%s \n", arr[0], chs[0], ls.get(0), person.name);
    
    引用传递_引用类型(arr,chs,ls,person);
    
    System.out.printf("引用传递_引用类型方法结束后=> " +
            "\n arr[0]=%d, chs[0]=%c,ls.get(0)=%d, person.name=%s \n", arr[0], chs[0], ls.get(0), person.name);
}
public static void 引用传递_引用类型(int[] arr, char[] chs, List<Integer> ls, Person personCopy){
    arr[0] = 2;
    chs[0] = '2';
    ls.set(0,2);
    personCopy.name = "李四";
    
    System.out.printf("引用传递_引用类型方法中=> " +
            "\n arr[0]=%d, chs[0]=%c,ls.get(0)=%d, person.name=%s \n", arr[0], chs[0], ls.get(0), personCopy.name);
}
public static class Person{
    public String name;
}

在这里插入图片描述

引用传递_引用类型方法执行前=> 
 arr[0]=1, chs[0]=1,ls.get(0)=1, person.name=张三 
引用传递_引用类型方法中=> 
 arr[0]=2, chs[0]=2,ls.get(0)=2, person.name=李四 
引用传递_引用类型方法结束后=> 
 arr[0]=2, chs[0]=2,ls.get(0)=2, person.name=李四 

通过底层原理理解

堆栈角度解释,Java是值传递。在Java中,当我们将一个变量从调用者的作用域传递到被调用的作用域时,传递的是变量的值(即其值,基本类型叫值,对象叫引用),而不是变量的内存地址。

值传递(基本数据类型传递)图解

对于基本数据类型,Java会进行栈上分配内存,传递的只是一份克隆数据,所以互不影响。

在这里插入图片描述

引用类型传递图解

对于引用数据类型,大部分情况下Java会进行堆上分配内存,栈上的person只是一个引用。person和personCopy是两个引用,但是都指向了同一个地址Person@60215eee,所以对这两个引用的对象内部进行修改导致的影响是一样的。

在这里插入图片描述

检验下你是否真的理解?

public static void main(String[] args) {
    Person person = new Person();
    person.name = "张三";
    System.out.printf("引用传递_引用类型方法执行前=> person.name=%s \n", person.name);
    引用传递_引用类型(person);
    System.out.printf("引用传递_引用类型方法结束后=> person.name=%s \n", person.name);
}
public static void 引用传递_引用类型(Person person){
    person = new Person();
    person.name = "李四";
}
public static class Person{
    public String name;
}

上面的代码【引用传递_引用类型方法结束后=>person.name=】输出什么?

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

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

相关文章

用c# 自己封装的Modbus工具类库源码

前言 Modbus通讯协议在工控行业的应用是很多的&#xff0c;并且也是上位机开发的基本技能之一。相关的类库也很多也很好用。以前只负责用&#xff0c;对其并没有深入学习和了解。前段时间有点空就在这块挖了挖。想做到知其然还要知其所以然。所以就有了自己封装的Modbus工具类库…

【鸿蒙开发】第十四章 Stage模型应用组件-任务Mission

1 任务(Mission)管理场景 任务&#xff08;Mission&#xff09;管理相关的基本概念如下&#xff1a; AbilityRecord&#xff1a;系统服务侧管理一个UIAbility实例的最小单元&#xff0c;对应一个应用侧的UIAbility组件实例。系统服务侧管理UIAbility实例数量上限为512个。 Mi…

C# winfroms使用socket客户端服务端代码详解

文章目录 1️⃣ 通信相关说明1.1服务端与客户端1.2 信息发送原理1.3 信息接收原理 2️⃣ socket代码2.1 客户端代码2.2 服务端代码 3️⃣ 定时任务处理报文3.1 Timers定时任务 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_4315141…

共基课程学习

序言 教育教师 政治基础知识 马克思主义哲学 西方哲学史 三个阶段 西方哲学的起源 圈1 圈2 圈3 第一个哲学高峰 希腊三贤 圈4 圈5 是故格拉底的学生 圈6 是柏拉图的学生 圈7、圈8 这是一个政教合一的社会 圈7 圈8 圈9 圈10 圈11 圈12 文艺复兴、启蒙运动共…

BlackberryQ10 是可以安装 Android 4.3 应用的,Web UserAgent 版本信息

BlackberryQ10 是可以安装 Android 4.3 应用的 最近淘了个 Q10 手机&#xff0c;非常稀罕它&#xff0c;拿着手感一流。这么好的东西&#xff0c;就想给它装点东西&#xff0c;但目前所有的应用都已经抛弃这个安卓版本了。 一、开发环境介绍 BlackBerry Q10 的 安卓版本是 4.…

计算机体系架构初步入门

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 目录 1 计算机五大…

Spring 中 ApplicationContext 和 BeanFactory 的区别有哪些

先看一张类图&#xff1a; 区别&#xff1a; 1&#xff1a;包目录不同&#xff1a; spring-beans.jar 中 org.springframework.beans.factory.BeanFactory spring-context.jar 中 org.springframework.context.ApplicationContext 2&#xff1a;国际化&#xff1a; BeanFacto…

c++之ini配置文件的详细解析

文章目录 ini文件概要代码实例分析小结 ini文件概要 ini文件是一种系统配置文件&#xff0c;它有特定的格式组成。通常做法&#xff0c;我们读取ini文件并按照ini格式进行解析即可。在c语言中&#xff0c;提供了模板类的功能&#xff0c;所以我们可以提供一个更通用的模板类来解…

【线程池项目(二)】线程池FIXED模式的实现

在上一篇【线程池项目&#xff08;一&#xff09;】项目介绍和代码展示 中&#xff0c;我们展示了线程池的两个版本实现&#xff0c;它们的代码在具体的实现细节上是优化过了的。下文提供的代码并非完整&#xff0c;也有很多地方尚需改善&#xff0c;但这些差异对理解整个项目而…

IT廉连看——C语言——分支语句

IT廉连看—分支语句 一、什么是语句 C语句可分为以下五类&#xff1a; 表达式语句 函数调用语句 控制语句 复合语句 空语句 本周后面介绍的是控制语句。 控制语句用于控制程序的执行流程&#xff0c;以实现程序的各种结构方式&#xff0c;它们由特定的语句定义符组成&…

字符串(算法竞赛)--字典树Trie与最大异或对

1、B站视频链接&#xff1a;F06 字典树(Trie)_哔哩哔哩_bilibili 题目链接&#xff1a;【模板】字典树 - 洛谷 #include <bits/stdc.h> using namespace std; const int N100010; int n; char s[N]; int ch[N][26];//ch[0][2]1表示0号节点通过c边走到了节点1 int cnt[…

2024最新前端面试题

数组是属于Object类型的&#xff0c;也就是引用类型&#xff0c;所以不能使用 typeof 来判断其具体类型。下面这些方法是判断数组的几种方法&#xff1a; 1、instanceof运算符 主要是判断某个实例&#xff08;arr&#xff09;是否属于某个对象。 let arr [1,2,3]; console.l…

eclipse中open Type 、 open type in Hierachy、open Resource的区别

目录 场景&#xff1a; open Type open Resource open type in Hierachy 场景&#xff1a; 在项目中想要研究底层代码&#xff0c;经常要用eclipse看依赖jar包的类&#xff0c;比如spring的源码中AbstractApplicationContext类CTLSHIFTT用的少&#xff0c;经常用的CTLSHIR…

给大家分享一款小程序:AI一秒修图

AI一秒修图 照片修复的AI助手特点&#xff1a;Demo&#xff08;1.选择图片 2.涂抹遮罩 3.消除&#xff09;Product Roadmap (版本演进)Contact-联系我们Reference 照片修复的AI助手 照片修复小小助手是一款快速P图微信小程序&#xff0c;用来消除图片中指定的人和物&#xff…

[算法沉淀记录] 排序算法 —— 冒泡排序

排序算法 —— 冒泡排序 基本概念 冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表&#xff0c;一次比较两个元素&#xff0c;并交换它们的位置&#xff0c;如果它们不是按照升序排列的。这步遍历是重复进行的&#xff0c;直到没有再需要交换&#xff0c;也就是说该…

【设计模式】策略模式及函数式编程的替代

本文介绍策略模式以及使用函数式编程替代简单的策略模式。 策略模式 在策略模式&#xff08;Strategy Pattern&#xff09;中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式定义了一系列算法或策略&#xff0c;并将每个算法封装在独立…

介绍 PIL+IPython.display+mtcnn for 音视频读取、标注

1. nn.NLLLoss是如何计算误差的? nn.NLLLoss是负对数似然损失函数&#xff0c;用于多分类问题中。它的计算方式如下&#xff1a;首先&#xff0c;对于每个样本&#xff0c;我们需要将其预测结果通过softmax函数转换为概率分布。softmax函数可以将一个向量映射为一个概率分布&…

Three.js加载PLY文件

这是官方的例子 three.js webgl - PLY 我在Vue3中使用&#xff0c;测试了好久始终不显示点云数据。在网上查询后发现ply文件要放置在public目录下才行 <el-row><el-button type"primary" class"el-btn" click"IniThree1">PLY</…

【C++初阶】--类和对象(下)

目录 一.const成员 1.权限放大问题 2.权限的缩小 二.再谈构造函数 1.构造函数体赋值 2.初始化列表 (1)概念 (2)使用 ①在对象实例化过程中&#xff0c;成员变量先依次进行初始化 ②再进行函数体内二次赋值 3.explicit关键字 (1)C为什么要存在自动隐式类型转换…

Java之线程同步、synchronized用法及原理

线程的同步 场景1&#xff1a;两个线程同时访问一个变量&#xff0c;一个线程自增&#xff0c;一个线程自减 public class thread11 {public static void main(String[] args) throws InterruptedException {Thread thread1 new AddThread();Thread thread2 new DecThread(…