传值类型_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位…

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

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

struts2整合uploadify插件怎样传参数

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

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

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

来自Java空间的传送门

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

来及Java空间的传送门2

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

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

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

实现页面适配_微信公众号文章页面适配深色模式

最近安卓微信7.0.10正式版发布&#xff0c;更新过后&#xff0c;很多用户发现&#xff0c;之前在测试版中对系统深色模式的适配功能被取消了&#xff0c;小伙伴们对此很是不满&#xff0c;好在Android 10系统手机用户占比很少&#xff0c;影响范围还不是很大&#xff0c;并且也…

iframe悬浮在html上_HTML Iframe

HTML Iframeiframe 用于在网页内显示网页。添加 iframe 的语法URL 指向隔离页面的位置。Iframe - 设置高度和宽度height 和 width 属性用于规定 iframe 的高度和宽度。属性值的默认单位是像素&#xff0c;但也可以用百分比来设定(比如 "80%")。实例&#xff1a;html&…

mysql 当前timestamp_MySQL表结构使用timestamp以自动获取当前时间

一、怀念ACCESS的时代ACCESS的表结构如果想自动插入当前时间的时候&#xff0c;可以在列定义的时候输入默认值now ()就可以实现自动插入当前时间了。而MySQL则行不通&#xff0c;MySQL这个东东默认是命令行下面的产物&#xff0c;如果不是后来有了phpMyAdmin这个图形化界面东东…

[转]如何设置win7一直以管理员身份运行

如何设置win7一直以管理员身份运行 在win7有些程序需要以管理员的身份才能运行&#xff0c;但是我们几乎天天都要运行这些程序&#xff0c;老是要手动选下很麻烦&#xff0c;怎么样设置才能这个程序以后运行都直接是以管理员的身份运行&#xff0c;不用在让我们去选择了&#x…

MySQL substring-index_mysql函数之SUBSTRING_INDEX(str,/,-1)

SUBSTRING_INDEX的用法&#xff1a; •SUBSTRING_INDEX(str,delim,count) 在定界符 delim 以及count 出现前&#xff0c;从字符串str返回自字符串。若count为正值,则返回最终定界符(从左边开始)若为-1则是从后往前截取SELECT substring_index(Hn_P00001, P, -1) -- 结果是0000…

integer 负数字符串比较_JAVA源码之Integer-1

四、方法toString三个方法&#xff0c;其中两个static方法。1、public String toString()&#xff1a;该方法内部使用toString(int i)实现。2、public static String toString(int i)&#xff1a;该方法内部使用stringSize方法巧妙的获取入参的size&#xff0c;然后用getChars把…

springboot mysql url_spring boot 连接Mysql介绍

Spring Boot 集成教程概述java应用的数据库接口的层次图如下JDBCJava应用通过JDBC接口访问数据库&#xff0c;JDBC(Java DataBase Connectivity/Java数据库连接)为各种数据库&#xff0c;如mysql、oracle等&#xff0c;提供一个统一的接口&#xff0c;应用程序通过JDBC执行各种…

python的遍历字典里的键然后放到一个列表里_Python列表和字典互相嵌套怎么办?看完让你没有疑惑...

文 | 猿天罡前言前两篇文章&#xff0c;我们学习了Python字典的基本用法和遍历字典的三种方式。为了让小伙伴们不耗费多余的注意力&#xff0c;我们举的例子都尽可能的简单&#xff0c;不信你回去看看&#xff0c;字典键对应的值都是基本数据类型(字符串、数字等)。其实&#x…

linux如查看是否安装了mysql_linux中如何查看mysql是否安装

linux中查看mysql是否安装的方法&#xff1a;1、mysql的守护进程是mysqld如果已经安装则:[rootlocalhost ~]# service mysqld start启动 MySQL&#xff1a; [确定]如果没有安装则:[rootlocalhost ~]# service mysqld startmysqld:未被识别的服务2、通过查看服务是否…

新鲜的宣传册设计

原文地址&#xff1a;http://www.goodfav.com/brochure-designs-9367.html 宣传画册设计印刷在品牌以及企业形象建设疏导方面扮演着非常重要的角色。宣传册设计是理想的营销材料。他们将帮助您建立有意向目标受众&#xff0c;提供有价值的信息。如果没有企业宣传册&#xff0c;…

mysql门派年龄最大的人_目前活着年龄最大的人

每逢老人过生日&#xff0c;子女都会祝他长命百岁&#xff0c;但事实上&#xff0c;长命百岁能过百岁的人少之又少。那么大家知道中国现在活着的最长寿的人是谁吗?下面让小编为大家揭晓答案吧!比正式的历史文献记载最长寿者年长14岁中新网曾对这一名黎巴嫩妇女进行报道&#x…

解决Gradle生成Eclipse支持后,发布到Tomcat丢失依赖jar包的问题

最近一个项目中&#xff0c;使用号称下一代构建工具的Gradle构建项目。 使用中发现一个问题&#xff0c;Gradle从中央库下载的jar文件在系统的其它目录&#xff0c;使用gradle eclipse添加Eclipse支持时&#xff0c;jar文件是以外部依赖的形式导入的。Eclipse将web项目发布到To…

mysql 执行计划_mysql执行计划

执行计划使用explain sql查询。1、 构造数据usecoshaho002;drop table if existsinfo;create tableinfo(idint primary keyAUTO_INCREMENT,namevarchar(32),agetinyint,sexvarchar(8),addressvarchar(32),phonevarchar(32),birthday date,descriptionvarchar(128));alter table…