传值类型_Java内存管理:Stackoverflow问答-Java是传值还是传引用(十一)

4a471aaf5c1d173cc8cd95179650221b.png

勿在流沙筑高台,出来混迟早要还的。

做一个积极的人

编码、改bug、提升自己

我有一个乐园,面向编程,春暖花开!

本文导图:

cc71752129870cd1c847a7f02a385b50.png

一、由一个提问引发的思考

在Stack Overflow 看到这样一个问题:

Is Java “pass-by-reference” or “pass-by-value”?

翻译成中文:

Java是传值还是传引用?

请先不要看下面的内容,思考10秒后,在继续阅读!!!

ae5b1f08c59fcb94fa9c6d4685aaecaa.png

为什么建议先思考,在阅读内容呢?

我们每天可能会利用碎片化的时间阅读很多内容,有很多信息和知识其实在大脑过一下,然后就忘记了!如何才能高效的利用碎片化时间掌握或者记住更多的内容和知识,我自己碎片化阅读的理解和技巧:阅读一篇自己感兴趣技术文章,在时间允许的时间下,一定是一次性阅读完,在阅读中带着自己的问题,阅读后有自己的简单总结。 千万不要阅读 一段内容,看到微信有人发消息给你,就切换聊天框回复消息,然后回复完再切换回来阅读技术文章。这种 大脑 的切换是需要耗费资源的,也影响阅读的效果和效率(大脑在多个任务切换类似cpu多线程调度,线程的频繁切换。就如多线程不一定能提供效率,频繁的线程/任务切换耗费cpu大量资源)!

扯远 了,切换回到本文正题,Java是传值还是传引用?

我相信你阅读完本篇后一定能够回答上面的问题,并且在工作在写类似传参的代码也会有更深入的理解。开启探索之旅,Let's go!

二、为什么有传值还是传引用的说法

在Java程序中会包含方法,方法会分为方法声明和方法实现,在方法声明中又有参数列表,参数根据调用后的效果不同,也就是是否改变参数的原始值,可以划分为两种: 按值传递参数和按引用传递参数。

  • 按值传递参数 == 传值
  • 按引用传递参数 == 传引用

也就是之前介绍过的Java的基本类型和引用类型,如果方法参数中传递的基本类型就认为是 按值传递(传值),方法参数中传递的是引用类型,就称之为按引用传递(传引用)。

三、图解传值和传引用过程

一段简单的代码:

public class PrettyGirl { /** * 芳龄几何 */ int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static void main(String[] args) { // 引用类型 PrettyGirl prettyGirl = new PrettyGirl(); prettyGirl.setAge(28); // 基本类型 int num = 50; // 数组arrs也引用类型 int[] arrs = new int[]{2,0,1,9}; System.out.println("mian 中 num = " + num); System.out.println("mian 中 arrs[3] = " + arrs[3]); System.out.println("mian 中 prettyGirl.getAge() = " + prettyGirl.getAge()); System.out.println("-----------------------------------------"); // 调用 change方法 prettyGirl.change(num, arrs, prettyGirl); System.out.println("调用change 后 mian 中 num = " + num); System.out.println("调用change 后 mian 中 arrs[3] = " + arrs[3]); System.out.println("调用change 后 mian 中 prettyGirl.getAge() = " + prettyGirl.getAge()); } public void change(int pnum, int[] parrs, PrettyGirl ppg) { //在change中 改变值类型pnum的值 pnum = pnum + 50; //在change中 改变引用类型 parrs,ppg 的值 parrs[3] = 8; // 从28变18 ppg.setAge(18); System.out.println("change 中 pnum = " + pnum); System.out.println("change 中 parrs[3] = " + parrs[3]); System.out.println("change 中 ppg.getAge() = " + ppg.getAge()); System.out.println("-----------------------------------------"); }}

思考一下,打印的结果是什么?

f985d9fcea91eb94165cb26c97a99883.png

打印结果如下

mian 中 num = 50mian 中 arrs[3] = 9mian 中 prettyGirl.getAge() = 28-----------------------------------------change 中 pnum = 100change 中 parrs[3] = 8change 中 ppg.getAge() = 18-----------------------------------------调用change 后 mian 中 num = 50调用change 后 mian 中 arrs[3] = 8调用change 后 mian 中 prettyGirl.getAge() = 18

下面开启分析之旅,结合之前学过的Java内存模型来画上面代码执行的内存变化的图

注:下图只是为了演示讲解说明,真实内存地址不一定是这样!

b69c00d19007fefd2f32919f131a72e8.png

int 类型变量num在栈中分配一块内存,而 parrs 与 ppg 分配两块内存,栈中一块,堆中一块。当调用change方法时,创建三个变量 pnum,parrs,ppg这里相当于把栈中的数据全备份一份给这三个数值,则有

5f15974312451dd1c3684ec14a6abc35.png

在change方法中对传递的参数进行修改,此时pnum的值修改为 100,堆中ppg指向的对象年龄由28改为18,数组中parrs[3]修改为8。也就是 ppg与 parrs 改变了堆中的具体数值,而 pnum 改变的只是栈中的数值。

3eef9fce9b60478fa5bfbd3181c515ab.png

最后,当change方法调用结束,change栈帧被弹出,则对应的pnum,ppg,parrs 三个变量也消亡,此时只有main栈帧情况如下图:

780d282376afc1506cee4d825ac4b571.png

通过上图的演示,上面代码的打印结果就很清晰明了了。


tips:回顾 java 栈

Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。

根据上面例子中这样的内存变换,想必你应该知道按值传递与按引用传递的深层原因了吧!

从上图中看所有的参数传递 本质都是按址值传递, 也就是内存地址的值 。 基本类型因为栈内存地址中保存就是其本身值,所有在参数传递的时候,拷贝本身的值进行传递,而引用类型在栈内存地址中保存的是引用的值,通过栈内存保存引用的值指向堆中获取对象真是的值,在参数传递的时候,拷贝的是引用的值。

所有在方法传递参数后,如果基本类型的值在传递的方法中有修改,不会影响传递前方法中的值。而引用类型就不同了,因为它修改的是引用地址指向堆中数据,这部分数据在参数传递的时候不会拷贝一份,就如上面图解标识出的一样。

四、本文总结

在Java中,对象通过引用传递,基本类型按值传递。

这句话的描述有一半是不准确的。就如上面我们图中看到的那样基本类型是按照值传递的; 引用类型是拷贝引用的址值传递的,也即对象通过引用传递。正确的描述语句是对象引用也是按值传递

其实在Java语言规范(JLS)中描述:Java 严格按值传递,可以理解与C完全相同,也就是Java中参数传递的本质是按址值传递。

如果你在阅读完本篇后,对上面问题有自己的深入的理解,有欢迎文末留言一起探讨!

参考文章

Is Java “pass-by-reference” or “pass-by-value”?

Java is Pass-by-Value, Dammit!


谢谢你的阅读,如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你每天开心愉快!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

愿你我在人生的路上能都变成最好的自己,能够成为一个独挡一面的人

© 每天都在变得更好的阿飞云

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

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

相关文章

java位运算(转)

位移动运算符: <<表示左移, 左移一位表示原来的值乘2. 例如&#xff1a;3 <<2(3为int型) 1&#xff09;把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011&#xff0c; 2&#xff09;把该数字高位(左侧)的两个零移出&#xff0c;其他的数字都朝左平移2位…

android图片的缩放、圆角处理

android中图片缩放方法有三种&#xff1a;1&#xff0c;bitmapFactory&#xff1b;2&#xff0c;bitmapmetrix&#xff1b;3&#xff0c;thumbUtil 方法一&#xff1a;bitmapFactory&#xff1a; public static Bitmap resizeBitmapByFactory(String path, int w, int h) {Bitm…

Navicat for MySQL介绍以及Navicat for MySQL基本使用方法

Navicat for MySQL是一款流行的MySQL图形化管理工具。 如何使用Navicat for MySQL连接MySQL服务器&#xff1f; 1.单击“连接”按钮&#xff0c;出现“新建连接”窗口。 2.分别输入连接名、MySQL 服务器主机地址、服务 端口号、用户名和密码&#xff0c;单击“确定” 按钮。…

python正则表达式怎么用_Python如何使用正则表达式

1. Python与正则表达式开始查看python当前如何通过使用re模式来支持正则表达式&#xff0c;re模式在古老的Python1.5版本中引入&#xff0c;用于替换哪些已经过时的regex模块和regsub模块---这两个模块在Python2.5版本中被移除&#xff0c;并且此后导入这两个模块中的任意一个都…

MySQL小白飞速成长记-运算符篇

运算符连接表达式中的各个操作数&#xff0c;其作用是指明对操作数所进行的运算。常见的运算有数学运算&#xff0c;比较运算和逻辑运算。运算符可以更加灵活地使用表中地数据&#xff0c;常见的运算符类型&#xff1a;算术运算符&#xff0c;比较运算符和逻辑运算符。 上面说…

批处理通过字符串截取得到文件名

当有一个完整的文件路径时&#xff0c;如何截取文件名呢&#xff0c;可以使用 echo 命令。 如下代码&#xff1a; echo off set a"E:\Program Files\Image-Line\FL Studio 9\FL.exe" set b"E:\Program Files\Image-Line\FL Studio 9\Plugins\VST\Revitar20\Effe…

可以批量转modis投影_SNAP批量处理Sentinel2数据

Sentinel-2数据以其高时空分辨率获得了越来越多的应用&#xff0c;然而由于Sentinel-2数据空间分辨率高&#xff0c;光谱分辨率高&#xff0c;数据量也较Landsat数据大幅上升。好在ESA SNAP软件批处理功能也很强大&#xff0c;可以支撑起大数据量的应用。下面就介绍一下如何使用…

MySQL表结构管理

今天我们来介绍一下MySQL数据类型&#xff0c;任何数据库中数据表的每个字段都必须设定数据类型&#xff0c;合适的数据类型可以有效的节省存储空间&#xff0c;有效的提升数据的计算性能&#xff0c;那么常见的数据类型有哪些呢&#xff0c;一起来看看吧 类型分类 类型 取值…

清空文件夹里面的所有文件和文件夹

private void deletefileOrDic(System.IO.DirectoryInfo path){try{foreach (System.IO.DirectoryInfo d in path.GetDirectories()){d.Delete(true);}foreach (System.IO.FileInfo f in path.GetFiles()){f.Delete();}}catch (Exception ex){}} 转载于:https://www.cnblogs.co…

涡轮增压扫地机器人_帮着做家务,好坏在哪里,科沃斯T5扫地机器人

小家电中要说对自己家里最有用的&#xff0c;其中之一就是扫地机器人&#xff0c;自从三年多前开始用了扫地机器人后&#xff0c;家里的地面是大为改观&#xff0c;劳动强度大为下降&#xff0c;可谓朕心甚慰。从此之后&#xff0c;一发不可收拾&#xff0c;用过也有20台以上的…

struts2整合uploadify插件怎样传参数

关于uploadify3.1&#xff0c;先看下帮助文档中的有些知识。 其中有个onUploadStart方法&#xff0c;我们可以使用这个向后台传参。 下面举个例子&#xff0c; js&#xff1a; <script type"text/javascript">$(function () {$(#actpic).uploadify({debug: fal…

教你正确把加减乘除运用在MySQL里面

加减乘除—>MySQL?相信在座的各位也想知道其中的奥秘&#xff1f;而这就不得不说到聚合函数&#xff0c;聚合函数用于对一组数据进行计算并返回一个汇总值&#xff0c;常用来统计记录行数&#xff0c;计算某个字段值的总和以及这些值的最大值&#xff0c;最小值和平均值等。…

对齐方式有那些_Excel基础:开始菜单之对齐方式,那些被遗忘的实用功能

今天小编要分享的Excel基础系列文章是"第三区块-对齐方式"。对齐方式主要是出来文字的排版问题&#xff0c;对齐方式包含的所有功能下面思维导图已经列出来。大多数功能都是我们常用的&#xff0c;也是比较简单的&#xff0c;这些功能小编就不说了&#xff0c;小编来…

来自Java空间的传送门

变量是程序中存储数据的基本单元&#xff0c;在该存储空间中&#xff0c;存储的数据值可以改变。 通过变量名可以简单快速地找到它存储的数据 使用Java的过程中我们需要注意一些细节&#xff0c;那就是Java语言的规范性了&#xff0c;比如Java的变量命名&#xff1a; 1.标识符…

python3转码python2_python2写的代码移植到python3后无法转码成中文文本,请大神指教,谢谢~...

chenmeiying(楼主)4天前C:\Users\www-3\AppData\Local\Programs\Python\Python36\python.exe C:/Users/www-3/Desktop/keyword_extraction-master/keyextract_word2vec_2.py b\xe8\xae\xbe\xe5\xae\x9a\xe5\x80\xbc b\xe8\xb8\xa9\xe4\xb8\x8b b\xe6\xb2\xb9\xe9\x97\xa8 b\xe4…

来及Java空间的传送门2

上一篇文章我们学习了Java的4种基本数据类型&#xff0c;今天我们就继续学习Java中的2种结构类型&#xff0c;分别是单分支结构&#xff0c;双分支结构和多重if结构 单分支结构&#xff1a;条件表达式的值必须为boolean类型 条件为true时执行if内的代码 双分支结构&#xff1…

UNIX环境高级编程——pthread_create的问题

linux 下常用的创建多线程函数pthread_create(pthread_t * thread , pthread_attr_t * attr , void *(*start_routine)(void*) , void *args);其中第一个参数用来保存线程信息&#xff0c;第二个参数指新线程的运行属性&#xff0c;可以设置为NULL&#xff0c;第三个参数为自定…

redis value最大值_Redis 的 maxmemory 和 dbnum 默认值都是多少?对于最大值会有限制吗?...

一、Redis 的默认配置了解 Redis 的都知道&#xff0c;Redis 服务器状态有很多可配置的默认值。例如&#xff1a;数据库数量&#xff0c;最大可用内存&#xff0c;AOF 持久化相关配置和 RDB 持久化相关配置等等。我相信&#xff0c;关于 AOF 持久化和 RDB 持久化的配置大家都很…

java成长之路

在Java语言中&#xff0c;一维数组的使用类似于变量的使用&#xff0c;分为以下4个步骤&#xff1a; 声明数组 创建数组 初始化数组 引用数组元素 语法&#xff1a;数据类型 [] 数组名 ; 或数据类型 数组名 []; int[] age; // 用于存储年龄 String names[]; // 用于存储…

程序员》推荐C++ 图书三人谈

程序员》推荐C 图书三人谈 主持人&#xff1a;熊节&#xff08;透明&#xff09;&#xff0c;《程序员》杂志编辑&#xff0c;C-View成员 嘉 宾&#xff1a;孟岩&#xff08;梦魇&#xff09;,联想公司掌上设备事业部应用开发处任职&#xff0c;C-View成员。与侯捷先生合译《C …