代码写的越急,程序跑得越慢。—— Roy Carlson

时间过得真快,2020已经过去了一半,但是疫情好像还没有真正的消灭,人们出行还是得带着口罩,天气越来越热,受罪啊。

言归正传,都2020年了,居然还有人认为java的参数传递方式是引用传递,今天我就来讲一讲java的参数传递,好好看,写的不对的地方,请大声说出来,反正我也不会改,憋坏了就不好了

基本数据类型传递

我们先来看一个普通的例子

package com.ymy.param;/*** @ProjectName: demo* @Package: com.ymy.param* @ClassName: BaseTypeTest* @Author: 流星007* @Description: 基本数据类型传递* csdn:https://blog.csdn.net/qq_33220089* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523* @Date: 2020/7/5 12:52* @Version: 1.0*/
public class BaseTypeTest {public static void main(String[] args) {int a = 1;dosomthing(a);System.out.println("主函数a的值 = "+a);}private static void dosomthing(int a) {a = a-1;System.out.println("修改过后,a = "+a);}
}

这是一个很简单的一个方法,在主函数main中对变量进行了初始化a=1,然后将a传递给dosomthing(),然后再dosomthing中输出了修改之后的值,最后在主函数中打印a的值,你们觉得这几句输出中a的值分别是多少呢?

第一种:
修改过后,a = 0
主函数a的值 = 1
第二种:
修改过后,a = 0
主函数a的值 = 0
第三种:
修改过后,a = 1
主函数a的值 = 1

想要得到答案的话就得先明白参数传递的两个类型:值传递和引用传递。

什么是引用传递?
在C++中,函数参数的传递方式有引用传递。所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

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

我们再回过头来看上面的例子,如果是引用传递的话打印结果应该是第二种情况,如果是值传递,打印结果应该是第一种情况,所以到底打印的结果是什么呢?

我们一起看一看控制台输出

Connected to the target VM, address: '127.0.0.1:59333', transport: 'socket'
修改过后,a = 0
主函数a的值 = 1
Disconnected from the target VM, address: '127.0.0.1:59333', transport: 'socket'Process finished with exit code 0

这就是第一种情况,很明显,在dosomthing函数中修改了a的值,但是主函数中的a并没有受到影响,所以肯定不会是引用传递,如果是引用传递,主函数的a应该会变成0,只有在参数传递的时候将主函数的中参数复制一份给dosomthing,才能在dosomthing中修改a不会对主函数造成影响,所以从基本数据类型来看,java的参数传递方式为:值传递

这个时候你可能会有疑问了,这只是基本数据类型的传递方式,其他的参数类型呢?下面我们一起来看看引用类型和对象类型的传递方式。

follow me !!!!!

引用类型传递

我们都知道java中的String类型不属于基本数据类型,它是一个引用类型,也可以说是一个对象,那么它的传递方式是什么呢?

我们还是先来看例子

package com.ymy.param;/*** @ProjectName: demo* @Package: com.ymy.param* @ClassName: StringTypeTest* @Author: 流星007* @Description: String类型传递* csdn:https://blog.csdn.net/qq_33220089* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523* @Date: 2020/7/5 14:22* @Version: 1.0*/
public class StringTypeTest {public static void main(String[] args) {String a = "hello";dosomthing(a);System.out.println("主函数a的值 = "+a);}private static void dosomthing(String a) {a = a+" bug";System.out.println("修改过后,a = "+a);}}

打印结果

修改过后,a = hello bug
主函数a的值 = helloProcess finished with exit code 0

我们发现主函数的a并没有受到dosomthing函数的影响,所以这并不是引用传递,这个时候你说是因为
a = a+" bug";这行代码生成了新的对象,所以才会导致数据不一致,我们先来看看a的赋值情况吧

// class version 52.0 (52)
// access flags 0x21
public class com/ymy/param/StringTypeTest {// compiled from: StringTypeTest.java// access flags 0x1public <init>()VL0LINENUMBER 14 L0ALOAD 0INVOKESPECIAL java/lang/Object.<init> ()VRETURNL1LOCALVARIABLE this Lcom/ymy/param/StringTypeTest; L0 L1 0MAXSTACK = 1MAXLOCALS = 1// access flags 0x9public static main([Ljava/lang/String;)V// parameter  argsL0LINENUMBER 17 L0LDC "hello"ASTORE 1L1LINENUMBER 18 L1ALOAD 1INVOKESTATIC com/ymy/param/StringTypeTest.dosomthing (Ljava/lang/String;)VL2LINENUMBER 19 L2GETSTATIC java/lang/System.out : Ljava/io/PrintStream;NEW java/lang/StringBuilderDUPINVOKESPECIAL java/lang/StringBuilder.<init> ()VLDC "\u4e3b\u51fd\u6570a\u7684\u503c = "INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;ALOAD 1INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)VL3LINENUMBER 21 L3RETURNL4LOCALVARIABLE args [Ljava/lang/String; L0 L4 0LOCALVARIABLE a Ljava/lang/String; L1 L4 1MAXSTACK = 3MAXLOCALS = 2// access flags 0xAprivate static dosomthing(Ljava/lang/String;)V// parameter  aL0LINENUMBER 24 L0NEW java/lang/StringBuilderDUPINVOKESPECIAL java/lang/StringBuilder.<init> ()VALOAD 0INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;LDC " bug"INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;ASTORE 0L1LINENUMBER 25 L1GETSTATIC java/lang/System.out : Ljava/io/PrintStream;NEW java/lang/StringBuilderDUPINVOKESPECIAL java/lang/StringBuilder.<init> ()VLDC "\u4fee\u6539\u8fc7\u540e\uff0ca = "INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;ALOAD 0INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)VL2LINENUMBER 27 L2RETURNL3LOCALVARIABLE a Ljava/lang/String; L0 L3 0MAXSTACK = 3MAXLOCALS = 1
}

这是上面代码的字节码代码,我们可以清楚的看到a在赋值的时候都调用了StringBuilder的同String方法,现在我们来看看这个神奇的同String方法。

@Overridepublic String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}

这是StringBuilder中的toString方法,确实是new了一个新的对象,就算是a变成了一个新的对象,如果是引用传递,主函数的a就不会受影响吗?这点我会讲完对象类型传递之后在进行讲解,请继续往下看。

对象类型传递

其实上面的两种其实很好区分,很多人都知道是值传递,很多人说java的传递方式是引用传递的原因就是出自这里:传递的参数为对象

有些人看到对象传递的时候会改变主函数的值,就认为java的参数传递是引用传递,有些人又因为基本数据类型不会队主函数的值造成修改,所以他们的结论是:基本数据类型为值传递;对象类型为引用传递,想法很好,那我们现在一起来解开对象传递的神秘面纱,它到底是引用传递还是值传递呢?

go go go !!!!

还是老规矩,我们一起来看一个例子

package com.ymy.param.vo;/*** @ProjectName: demo* @Package: com.ymy.param.vo* @ClassName: LolVo* @Author: 流星007* @Description: lol英雄属性* csdn:https://blog.csdn.net/qq_33220089* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523* @Date: 2020/7/5 15:11* @Version: 1.0*/
public class LolVo {/*** 姓名*/private String name;/*** 职业*/private String profession;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getProfession() {return profession;}public void setProfession(String profession) {this.profession = profession;}@Overridepublic String toString() {return "LolVo{" +"name='" + name + '\'' +", profession='" + profession + '\'' +'}';}
}
package com.ymy.param;import com.ymy.param.vo.LolVo;/*** @ProjectName: demo* @Package: com.ymy.param* @ClassName: ObjectTypeTest* @Author: 流星007* @Description: 对象类型传递* csdn:https://blog.csdn.net/qq_33220089* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523* @Date: 2020/7/5 15:16* @Version: 1.0*/
public class ObjectTypeTest {public static void main(String[] args) {LolVo lolVo = new LolVo();lolVo.setName("无极剑圣");lolVo.setProfession("刺客");dosomthing(lolVo);System.out.println("主函数 lolVo = "+lolVo);}private static void dosomthing(LolVo lolVo) {lolVo.setProfession("战士");System.out.println("dosomthing lolVo = "+lolVo);}}

结果如下:

dosomthing lolVo = LolVo{name='无极剑圣', profession='战士'}
主函数 lolVo = LolVo{name='无极剑圣', profession='战士'}Process finished with exit code 0

主函数中剑圣的职业是刺客,在dosomthing中将他修改成,我们发现主函数中剑圣的职业也被修改成战士了,显然这符合引用传递的条件,被调用方修改会影响到调用方也就是主函数,所以这个时候很多人就认为java的对象传递的方式为引用传递,如果你也是这么认为,那么你就要认真看一下我后面的分析。

我们先来一个否定它是引用传递的例子,请看好,不要眨眼

package com.ymy.param;import com.ymy.param.vo.LolVo;/*** @ProjectName: demo* @Package: com.ymy.param* @ClassName: ObjectTypeTest* @Author: 流星007* @Description: 对象类型传递* csdn:https://blog.csdn.net/qq_33220089* 今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523* @Date: 2020/7/5 15:16* @Version: 1.0*/
public class ObjectTypeTest {public static void main(String[] args) {LolVo lolVo = new LolVo();lolVo.setName("无极剑圣");lolVo.setProfession("刺客");dosomthing(lolVo);System.out.println("主函数 lolVo = "+lolVo);}private static void dosomthing(LolVo lolVo) {lolVo = new LolVo();lolVo.setProfession("战士");System.out.println("dosomthing lolVo = "+lolVo);}}

做了小小的改动,仅仅只是在dosomthing方法中加了一行代码:lolVo = new LolVo();

我们再来看运行结果是什么呢?还会和上面一样吗?

dosomthing lolVo = LolVo{name='null', profession='战士'}
主函数 lolVo = LolVo{name='无极剑圣', profession='刺客'}Process finished with exit code 0

我们发现主函数中剑圣的属性变回了刺客,并没有受到dosomthing函数的影响,如果是引用传递的话,主函数中剑圣的职业应该是战士而不是刺客。这是为什么呢?为什么是应用传递主函数中剑圣的职业因该是战士呢?

下面我们一起来分析一波

我们假设对象的传递方式为引用传递

这是堆栈中的信息,当我们将对象lolVo传递给dosomthing的时候,是克隆了一个对象出来还是原来的那个对象呢?我们知道,不管传递的是不是它本身,值都是内存的地址引用,我们现在先假设主函数没有复制,是直接将lolVo传递给了dosomthing,那图形应该是什么样的呢?

如果是引用传递,格式是不是应该是这样呢?main主函数和dosomthing函数公用一个lolVo,这个时候我们在dosomthing函数中执行了一句:lolVo = new LolVo();
那又会变成什么样呢?

在dosomthing方法中我们new了一个新的LolVo对象,并且将这个新的对象赋值给了lolVo,那是不是代表着main主函数核dosomthing函数中的lolVo应该是一样的呢,我们再来回顾一下上面的代码

private static void dosomthing(LolVo lolVo) {lolVo = new LolVo();lolVo.setProfession("战士");System.out.println("dosomthing lolVo = "+lolVo);}

我们做了修改之后,主函数剑圣的职业并没有修改成战士,所以,说java是引用传递是说不通的,闹我们再来看看它正确的流程应该是什么样的呢?


尽管dosomthing对参数的修改会影响调用方,但是它还是属于值传递,会影响调用方是因为java转递的时候拷贝的是对象的引用地址。

举个栗子:比如某公司开发了一套员工的内部管理系统,有一个管理员的账号,你把这个账号给了你的同事,他直接使用你这个账号,这就是引用传递,如果你是在用户管理中添加了一条管理员的用户,再将这个账号给你的同事,这就是值传递,还需要解释一下,为什么值传递会影响调用方,如果你给痛的账号,你同事改了用户名称,这对你是不是没有影响,但如果他手抖把员工全删了,你这边还能看到员工信息吗?就是这个道理,lolVo引用地址相当于管理员账号,系统内的功能相当于LolVo对象,你修改自己的账号对别人当然没有影响,但是你把系统搞没了,你觉得有影响吗?这就是为什么java的参数传递方式为值传递却能影响调用方。

总结

文章发布了一会就有人说java的参数传递方式是引用传递,我呢,如果你说的是对的,那我会虚心接受,所以我就认为我的讲解除了问题,然后我就去oracle官方找了一波,官方给出的也是值传递。

英文看不懂?那就右击翻译成中文

官方demo地址:https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
如果还有人和你说java的参数传递是引用传递的话,请他来看一下我这篇博客,我把他劝退一下。

天真,居然还有人认为java的参数传递方式是引用传递相关推荐

  1. python学什么版本2020年_2020年了居然还有人在学Python?学python有什么用?

    都2020年了居然还有人在学python?学python有什么用? 真是气抖冷啊! 想学习python的小伙伴,可以加裙595227871 领取免费的学习资料 为什么选择python? 1.行业人才的 ...

  2. java值传递和引用传递_辨析Java方法参数中的值传递和引用传递

    小方法大门道 小瓜瓜作为一个Java初学者,今天跟我说她想通过一个Java方法,将外部变量通过参数传递到方法中去,进行逻辑处理,方法执行完毕之后,再对修改过的变量进行判断处理,代码如下所示. publ ...

  3. Java里的按值传递与引用传递

    按值传递还是按引用传递 这个在Java里面是经常被提起的问题,也有一些争论,似乎最后还有一个所谓的结论:"在Java里面参数传递都是按值传递".事实上,这很容易让人迷惑,下面先分别 ...

  4. Java基础中按值传递和引用传递详解

    下面是我在网上看到的一个帖子,解释的感觉挺全面,就转过来,以供以后学习参考: 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: [java] view plaincopy ...

  5. 震惊!居然还有人不懂二叉树!99%的程序员都会了,不会就点进来吧!

    什么!你居然点进来了!看来你就是那百分之一的程序员吧.既然不懂什么是二叉树,那我就来给你讲讲. 1. 树 所谓二叉树,本质上还是个树呀,想要知道什么是二叉树,就要了解树是什么样子的.纳尼!树是什么样子 ...

  6. java好玩吗_现在还有人觉得java有趣吗?

    有趣呀! 我用过的编程语言不多,先后顺序为 C.Perl.Java.PHP.Javascript.Python.这些都是实际工作中用了的,写个 Hello world 体验下的不算. 这里面要说有趣, ...

  7. 居然还有人在用 System.out.println打日志的吗?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 雨尔辰辰 来源 | my.oschina.ne ...

  8. 这6部超经典的物理电影,居然还有人没有看过?

    全世界只有3.14 % 的人关注了 爆炸吧知识 开篇警告:这是一篇福利文! 今天小编给热爱物理及数学的小伙伴们,分享6部豆瓣评分8分以上,与数学和物理领域相关的经典电影,帮助大家在工作.学习之余劳逸结 ...

  9. 居然还有人在手写测试数据?

    平时我们在开发程序的时候,总免不了需要造一些假数据来验证自己的程序功能是否正常.那么你是通过什么方式来造假数据的呢,不会每次都是手写「测试数据.test」吧. 今天派森酱给大家介绍两个超级好用的库,批 ...

最新文章

  1. 【多线程高并发】深入理解JMM产生的三大问题【原子性、可见性、有序性】
  2. elxel表格纸张尺寸_纸张知识|克重厚薄多少,正度大度纸开本尺寸规格是什么大小,和A4有啥区别?...
  3. 如何在ubuntu中编写python_在ubuntu下编写python(python入门)
  4. ARMv8体系结构基础04:算术和移位指令
  5. 使用nvl就不能groupby了吗_现在的手机大部分都不能换电池,使用1至2年就需要更换吗?...
  6. 微弱信号检测matlab,微弱信号检测
  7. postman接口测试工具的使用攻略
  8. 海外版mate9刷机国行android 8.0系统
  9. EFCore-脚手架Scaffold发生Build Failed问题的终极解决
  10. 强烈推荐这 15 个网站!
  11. java标识符规范书写的规则
  12. python画国旗和八卦图
  13. Dart | Flutter 中的异常处理框架 Talker
  14. 【技术分享】链路聚合
  15. iphone为什么不能连接到服务器未响应,苹果手机(iPhone)连接电脑没反应?(这样就可以解决!)...
  16. 【转】Mac突然连不上WiFi解决步骤
  17. 有序有重复、有序无重复、无序无重复、无序有重复区别详解及Python实现
  18. U盘显示打开设备和打印机--Linux系统(Ubuntu18.04)解决方案
  19. 最新Mysql 8.0.27安装指南
  20. 盲盒生意怎么做?电商盲盒哪里找货源批发?

热门文章

  1. [ASP.NET]如何把Popup特性从宝玉的论坛代码中拆分出来呢?
  2. 挥一挥笔,江南在素笺上起舞
  3. 脑子不灵活适合学计算机吗,开学就初三了,初一初二什么也不学但是老师都说我脑子灵活不知道初三能学好吗...
  4. Bagging与Boosting算法的原理与区别,Boosting算法之一Adaboost原理与代码实现
  5. C#服务器NFS共享文件夹搭建与上传图片文件
  6. 安装Python编译器
  7. matlab做概率论题,Matlab 概率论与数理统计.doc
  8. 计算机桌面下方标图,怎么把电脑下面的图标显示大
  9. Pytorch实现SqueezeNet
  10. 佛教追求的不是信仰,而是觉悟!佛,就是觉悟的人!