按值传递还是按引用传递

2023-10-27

 

这个在Java里面是经常被提起的问题,也有一些争论,似乎最后还有一个所谓的结论:“在Java里面参数传递都是按值传递”。事实上,这很容易让人迷惑,下面先分别看看什么是按值传递,什么是按引用传递,只要能正确理解,至于称作按什么传递就不是个大问题了。

1:按值传递是什么
指的是在方法调用时,传递的参数是按值的拷贝传递。示例如下:

public class TempTest {
private void test1(int a){
//做点事情
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//这里传递的参数a就是按值传递
}
}

按值传递重要特点:传递的是值的拷贝,也就是说传递后就互不相关了。
示例如下:

public class TempTest {
private void test1(int a){
a = 5;
System.out.println("test1方法中的a==="+a);
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//传递后,test1方法对变量值的改变不影响这里的a
System.out.println(”main方法中的a===”+a);
}
}

运行结果是:
test1方法中的a===5
main方法中的a===3

2:按引用传递是什么
指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。
示例如下:

public class TempTest {
private void test1(A a){

}
public static void main(String[] args) {
TempTest t = new TempTest();
A a = new A();
t.test1(a); //这里传递的参数a就是按引用传递
}
}
class A{
public int age = 0;
}

3:按引用传递的重要特点
传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。
示例如下:

第1行 public class TempTest {
第2行 private void test1(A a){
第3行 a.age = 20;
第4行 System.out.println("test1方法中的age="+a.age);
第5行 }
第6行 public static void main(String[] args) {
第7行 TempTest t = new TempTest();
第8行 A a = new A();
第9行 a.age = 10;
第10行 t.test1(a);
第11行 System.out.println(”main方法中的age=”+a.age);
第12行 }
第13行 }
第14行 class A{
第15行 public int age = 0;
第16行 }

运行结果如下:
test1方法中的age=20
main方法中的age=20

4:理解按引用传递的过程——内存分配示意图
要想正确理解按引用传递的过程,就必须学会理解内存分配的过程,内存分配示意图可以辅助我们去理解这个过程。
用上面的例子来进行分析:
(1):运行开始,运行第8行,创建了一个A的实例,内存分配示意如下:

(2):运行第9行,是修改A实例里面的age的值,运行后内存分配示意如下:

(3):运行第10行,是把main方法中的变量a所引用的内存空间地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽。

内存分配示意如下:

由于是按引用传递,也就是传递的是内存空间的地址,所以传递完成后形成的新的内存示意图如下:


也就是说:是两个变量都指向同一个空间。

(4):运行第3行,为test1方法中的变量a指向的A实例的age进行赋值,完成后形成的新的内存示意图如下:

此时A实例的age值的变化是由test1方法引起的

(5):运行第4行,根据此时的内存示意图,输出test1方法中的age=20
(6):运行第11行,根据此时的内存示意图,输出main方法中的age=20

5:对上述例子的改变
理解了上面的例子,可能有人会问,那么能不能让按照引用传递的值,相互不影响呢?就是test1方法里面的修改不影响到main方法里面呢?
方法是在test1方法里面新new一个实例就可以了。改变成下面的例子,其中第3行为新加的:


第1行 public class TempTest {
第2行 private void test1(A a){
第3行 a = new A();//新加的一行
第4行 a.age = 20;
第5行 System.out.println("test1方法中的age="+a.age);
第6行 }
第7行 public static void main(String[] args) {
第8行 TempTest t = new TempTest();
第9行 A a = new A();
第10行 a.age = 10;
第11行 t.test1(a);
第12行 System.out.println(”main方法中的age=”+a.age);
第13行 }
第14行}
第15行class A{
第16行 public int age = 0;
第17行}

运行结果为:
test1方法中的age=20
main方法中的age=10

为什么这次的运行结果和前面的例子不一样呢,还是使用内存示意图来理解一下

6:再次理解按引用传递
(1):运行开始,运行第9行,创建了一个A的实例,内存分配示意如下:

(2):运行第10行,是修改A实例里面的age的值,运行后内存分配示意如下:

(3):运行第11行,是把main方法中的变量a所引用的内存空间地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽。

内存分配示意如下:

由于是按引用传递,也就是传递的是内存空间的地址,所以传递完成后形成的新的内存示意图如下:

也就是说:是两个变量都指向同一个空间。

(4):运行第3行,为test1方法中的变量a重新生成了新的A实例的,完成后形成的新的内存示意图如下:

(5):运行第4行,为test1方法中的变量a指向的新的A实例的age进行赋值,完成后形成的新的内存示意图如下:

注意:这个时候test1方法中的变量a的age被改变,而main方法中的是没有改变的。

(6):运行第5行,根据此时的内存示意图,输出test1方法中的age=20
(7):运行第12行,根据此时的内存示意图,输出main方法中的age=10

7:说明
(1):“在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。
(2):在Java里面只有基本类型和按照下面这种定义方式的String是按值传递,其它的都是按引用传递。就是直接使用双引号定义字符串方式:String str = “Java私塾”;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

按值传递还是按引用传递 的相关文章

  • 内部/匿名类的最佳实践[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 匿名类和静态内部类的最佳实践 设计和性能方面 是什么 就我个人而言 我认为静态内部类提供了更好的封装 并且应该提供更好的性能 因为它们无法访问类
  • 不区分大小写的 NSString 比较

    使用此代码我可以比较字符串值 elementName isEqualToString Response 但这是区分大小写的 有没有办法比较字符串而不区分大小写 有一个caseInsensitiveCompare 方法上NSString 你为
  • 带嵌入式 tomcat 的 spring-boot 不会将请求分派到控制器

    我有一个使用 spring boot 和嵌入式 Tomcat 容器的应用程序 据我所知 我的代码与 spring boot 相同示例项目 https github com spring projects spring boot tree m
  • 竞争条件和 Clojure Atoms

    clojure atom 的文档指出 Changes to atoms are always free of race conditions 然而 竞争条件不仅是根据更改定义的 而且是在不同线程中并行逻辑操作的上下文中定义的 我想知道 保证
  • C++ - 如何从类的构造函数中初始化单独类的构造函数?

    基本上我想要实现的是创建该类的本地 和私有 实例deltaKinematics在课堂里geneticAlgorithm In the geneticAlgorithm h我有的文件 class DeltaKinematics class i
  • 如何从 Java 生产代码中删除调试语句

    编译器是否可以从生产代码中删除用于调试目的 例如日志记录 的语句 调试语句需要以某种方式进行标记 可能使用注释 设置属性 debug true 并在每个调试语句中检查它很容易 但这会降低性能 如果编译器能够简单地使调试语句消失 那就太好了
  • 字符串 a == 字符串 b 的规则 [重复]

    这个问题在这里已经有答案了 我试图了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是什么 例如这个片段 public static void main String hi String s1 lol String s2 lol S
  • 基于磁盘的 HashMap [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Java 是否有 或者是否有可用的库 允许我拥有基于磁盘的 HashMap 它不需要是原子的或任何东西
  • 如何在不冒 StackOverflowError 风险的情况下使用 CompletableFuture?

    我想遍历异步函数的搜索空间 我将逻辑编码如下 Assuming that a function maps a range of inputs to the same output value minimizes the input valu
  • Swift 1.2 和 Swift 2.0 中的字符串长度[重复]

    这个问题在这里已经有答案了 在以前版本的 Swift 中 我有以下代码 func myfunc mystr String if mystr utf16Count gt 3 使用最新版本的 Swift 1 2 我现在收到以下错误 utf16C
  • 在休眠搜索中使用现有分析器AnalyzerDiscriminator

    Entity Indexed AnalyzerDefs AnalyzerDef name en tokenizer TokenizerDef factory StandardTokenizerFactory class filters To
  • 错误包括 bouncycastle 提供商

    我需要使用bouncycastle provider我的项目中的库 我已将其包含在 gradle 项目中 apply plugin application sourceCompatibility 1 6 version 1 0 0 main
  • 用二进制数、常规数字和格雷编码填充矩阵

    我有一个包含 1 s 或 0 s 的矩阵 用于创建二进制数 其宽度为n 对于 n 2 和 n 3 它看起来像 00 000 01 001 10 010 11 011 100 101 110 111 等等 现在我正在使用以下代码来生成它 in
  • 将序列化数据发送到 servlet 时出现 java.io.EOFException

    我正在尝试从 Java 本地应用程序上传一个包含文件到服务器的对象 我的计划是 在 tomcat 上运行的 servlet 将使用以下方法获取对象ObjectInputStream in the doGet方法 但我得到一个EOFExcep
  • Java 日期和 MySQL 时间戳时区

    我正在编辑一段代码 其基本功能是 timestamp new Date 然后坚持下去timestamp中的变量TIMESTAMPMySQL 表列 然而 通过调试我看到Date显示在正确时区的对象 GMT 1 当持久化在数据库上时 它是GMT
  • jasper 报告文件中出现错误

    首先 我在 iReport 5 1 0 中创建一个 R D1 jrxml 文件 我执行该报告的 Java 代码如下所示 import java sql Connection import java sql DriverManager imp
  • 如何预先填充 JFileChooser 将“文件名”?

    我打算用数据库中的名称填充 JFileChooser 但使用标准 JFileChooser 对话框进行加载 删除 保存和另存为 我想给用户留下这样的印象 他们正在处理文件系统 而在后端使用数据库来保存更改 用户不应该能够浏览到不同的目录进行
  • 在python中将列表转换为字符串

    我对 python 语言相当陌生 我一直在寻找这个问题的答案 我需要一个如下所示的列表 Kevin went to his computer He sat down He fell asleep 转换为如下字符串 Kevin went to
  • SWT StyledText 有高度限制吗?

    我正在尝试创建一个应用程序 其中包含在 ScrolledComposite 中显示的 StyledText 框 我在 StyledText 框中显示大量行时遇到困难 超过 2 550 行似乎会导致问题 StyledText 框本身不能有滚动
  • 与手动搜索列表相比,Collections.binarySearch 的性能如何?

    我想知道该使用哪一个 我有一份学生名单 我想用他的名字搜索一个学生 到目前为止 我是通过迭代列表手动完成的 如下所示 for int i 0 i lt list size i Student student list get i if st

随机推荐

  • java base64转字图片、图片转base64字符串

    实现代码如下 Slf4j public class Base64ToFileImageTools base64字符串转化成图片 param imgData 图片编码 param imgFilePath 存放到本地路径 return thro
  • 2021 全球人工智能技术创新大赛 医学影像报告异常检测 TOP4方案

    2021 全球人工智能技术创新大赛 医学影像报告异常检测 TOP4方案 1 写在前面 在本次全球人工智能技术创新大赛赛道一的比赛中 我们团队水煮毛血旺以初赛第三 复赛第四的成绩进入了决赛 最终决赛排名第四 本文主要想记录一下这次比赛的方案以
  • docker创建python、jdk环境并保存镜像,运行容器

    在本地任一台可联网服务器上 创建容器 1 首先确定系统的版本 拉取镜像 docker pull centos 7 4 1708 2 创建容器 docker run i t centos 7 4 1708 bin bash 3 在容器中安装所
  • Quartus18.1 lite免费教育版下载及安装

    目录 一 下载 1 首先注册intel官网账号 2 进入下载界面找到Quartus18 1教育版 3 下载项目 二 安装 一 下载 intel官网 www intel cn 1 首先注册intel官网账号 随便在官网注册个账号 国内的邮箱也
  • 如何快速做一个微信自动拉群机器人 足够简单 足够粗暴

    wechaty 首先 wechaty了解一下 文档链接 https docs chatie io v zh 只需要6行代码 你就可以通过个人号搭建一个微信机器人功能 用来自动管理微信消息 是不是很简单很粗暴 const Wechaty re
  • STM32 HAL库 时钟芯片RX8025T IIC的读写操作,入过的坑

    我使用STM32本身的IIC外设 与时钟芯片RX8025T进行通信 时钟芯片RX8025特点 高精度 据说每个月时钟误差在1秒以内 做流量计这些需要精密控时的东西 完全够用了 一 时钟芯片RX8025T简单说明 重要 RX8025芯片有二种
  • 图论模型(Dijkstra算法和Floyd算法)

    图论模型 图论模型 Dijkstra算法 概念 带权邻接矩阵 代码 操作 Floyd算法 概念 代码 操作 Dijkstra算法 概念 Dijkstra算法能求一个顶点到另一顶点最短路径 它是由Dijkstra于1959年提出的 实际它能给
  • C++之获取网卡物理地址(MAC)

    ConsoleApplication1 cpp 定义控制台应用程序的入口点 include stdafx h include
  • QT5.15离线安装

    在线安装后 将所有的资源打成压缩包 拷贝至另外一台电脑 进行如下设置 1 解压 2 进入路径 QT Tools sdktool share qtcreator QtProject 3 修改QtCreator ini 将所有的绝对路径修改为实
  • 搜狐新闻算法原理

    转载 搜狐新闻推荐算法原理 导读 在当前这个移动互联网时代 各种信息内容爆炸 面对海量数据 用户希望在有限的时间和空间内 找到自己感兴趣的内容 这就是推荐需要解决的问题 接下来主要讲解新闻推荐的算法原理 01 新闻推荐算法架构 新闻算法的核
  • Python招聘网站爬虫:从招聘网站获取职位信息进行职位搜索和分析的完整指南

    目录 1 简介 1 1 什么是招聘网站爬虫 1 2 爬虫的法律和道德问题 2 准备工作
  • 第二个重要极限的证明 e怎么出来的

    第二个重要极限的证明 e怎么出来的 具体步骤是什么啊 匿名 浏览 4402 次 推荐于2017 05 24 13 27 43 最佳答案 1 对于数列 重要极限的 e 是定义出来的 2 对于函数 重要极限的 e 是推导出来的 请楼主耐心参看下
  • 【VAR

    以美国 GDP 和通货膨胀数据为例 1 数据集 下载数据我们需要从 FRED 数据库下载美国 GDP 和通货膨胀数据 并将它们存储在 CSV 文件中 可以在 FRED 网站 https fred stlouisfed org 搜索并下载需要
  • AOP的底层实现--ASM

    在ASM的核心组件中 Opcodes接口定义了一些常量 尤其是版本号 访问标识符 字节码等信息 ClassReader用于读取Class文件 它的作用时进行Class文件的解析 并可以接受一个ClassVisitor ClassReader
  • OrderedDIct有序字典

    有序字典 与正常字典一致 只是会保留插入时的顺序 创建有序字典 不过由于多了保留顺序的功能 因此在使用可迭代对象创建有序字典时 可以先对它排个序 让创建出来的字典元素也是有序的 import collections data a 1 b 3
  • Codeblocks converting to execution character set: Illegal byte sequence错误解决办法

    Codeblocks converting to execution character set Illegal byte sequence错误解决 依次点击Settings gt Compiler 然后点击 Other compiler
  • InputStream 转成 MultipartFile

    1 转换中我们会使用MockMultipartFile这个类 所有要引用相应包
  • 持续集成-CI/CD流程图

    持续集成 持续集成强调对于开发人员的每个提交 立刻进行构建 扫描 单元 测试 根据结果 我们可以确定新代码和原有代码能否正确地集成在一起 持续交付 持续交付在持续集成的基础上 将集成后的代码部署到更贴近真实运行环境的 类生产环境 中进行更多
  • vs2019 应用程序无法正常启动(0xc000007b)

    编译程序时报错 应用程序无法正常启动 0xc000007b 不要慌 小问题 在使用vs编译器时偶尔会出现如下这种情况 这很大可能与 dll文件有关 解决方法 一 动用你的小手 请把这里的x64或者下x86切换一下 然后再进行编译 如果还没有
  • 按值传递还是按引用传递

    这个在Java里面是经常被提起的问题 也有一些争论 似乎最后还有一个所谓的结论 在Java里面参数传递都是按值传递 事实上 这很容易让人迷惑 下面先分别看看什么是按值传递 什么是按引用传递 只要能正确理解 至于称作按什么传递就不是个大问题了