用画小狗的方法来解释Java中的值传递


在开始看我画小狗之前,咱们先来看道很简单的题目:

 
下面程序的输出是什么?



如果你的回答是“小强”,好,恭喜你答对了。下面我们改一下代码:



是的,我只是在changeName方法里面加了一句代码



这一次的输出又是什么呢?

A、旺财 

B、小强


答案是A、旺财,changeName方法并没有把myDog的名称改了。如果你答错了,没关系,我要开始画小狗了,画完你就明白了;如果你答对了,但不太明白其中的原因,那我画的小狗也肯定能帮到你。


myDog是什么


首先你要搞懂,代码里的变量myDog是什么?myDog真的就是一只狗吗?不!不是!myDog只是一条遛狗用的狗绳!



换句话说说,myDog并不是new出来的放在堆中的对象(object)!myDog只是一个指向这个对象实例的引用(reference)!


如果你对Java的运行时数据区域足够了解,应该知道,这个引用是放在虚拟机栈上的。


参数传递


现在你知道了,myDog只是一条绳子,但这似乎并不能解释为什么changeName方法没有把myDog的名称改为“小强”,因为按照现有的理解,dog = new Dog(),就是把我的狗绳绑到另一只小狗身上,然后给这只小狗起名为“小强”,就像这样:



可事实是,myDog还是叫旺财,这是为什么? 


问题就出在方法调用上。


当我执行changeName(myDog)这一行代码时,myDog这条狗绳,被复制了一份,而传入到changeName方法里的那条狗绳(dog),就是复制出来的那一条,就像这样:



接着执行dog= new Dog(),这一行代码,就是把复制出来的那一条狗绳,从myDog解绑,重新绑到new出来的那只小狗上,也就是后来被起名为“小强”的小狗:


而myDog还是绑在旺财身上,这也就解释了,为什么执行完方法出来,myDog.getName()还是旺财。而在第一段代码里面,我们没有执行dog= new Dog(),也就没有改变dog所绑的小狗,dog还是绑在旺财身上,因此dog.setName(“小强”) 就把旺财的名字改成小强了。


string的例子


我们再来看一个例子:



如果你弄懂了上面那个例子,那么这里应该不难理解,changeString方法里,只是将新复制出来的引用str,指向另外一个字符串常量对象“bbb”,方法体外面的str并不受影响,还是指向字符串常量“aaa”,因此最终打印的还是aaa。


int的例子


上面提到的都是对象,下面看一个基本数据类型的例子



对于基本数据类型,他们没有引用,但是不要忘了,调用函数时,复制的动作还是会做的,执行changeInt(i)时,会将 i 复制到一个新的int上,传给changeInt方法,因此不管changeInt内部对入参做了什么,外面的 i 都不会受影响。最后打印出来的还是1。


值传递和引用传递


上面提到的参数传递过程中的复制操作,说白了,就是 = 操作。把上面那个int例子,做一下方法内联,其实就是这样:



对于基本数据类型,= 操作将右边的变量(R_VALUE)完整的复制给左边的变量(L_VALUE),而对于对象,准确的说,应该是指向对象的引用(就像上面说的myDog),= 操作同样也是将右边的引用完整的复制给左边的引用,两者指向同一个对象实例。 


这个 = 操作,是值传递和引用传递的根本差别,这也导致了值传递和引用传递有以下直观上的差别


如果参数是值传递,那么调用者(方法体外部)和被调用者(方法体内部)用的是两个不同的变量,方法体里面对变量的改动不会影响方法体外面的变量。而之所以在Java可以在方法体内部改变方法体外部的对象,是因为方法体内部拿到了对象的引用,但是这个引用是和方法体外部的引用属于两个不同的引用的,方法体内部的引用指向别的对象,不会导致方法体外部的引用也指向别的对象。


如果参数是引用传递,那么调用者(方法体外部)和被调用者(方法体内部)用的是两个相同的变量,方法体里面对变量的改动会影响方法体外面的变量。


Java的变量都不是对象


通过上面的讲解,你也知道了一个很重要的点:Java里面的变量,要么是基本数据类型,要么是指向对象实例的引用类型(狗绳),绝对不会是一个对象(狗)。


狗绳和垃圾回收


弄懂了myDog只是一条狗绳(引用),也有助于我们理解Java的垃圾回收机制一旦JVM发现一个对象跟GC Roots不可达时,这个对象就会被回收掉


看一下下面这段代码:



现在我们知道,dog=null就等于是把狗绳给咔嚓减掉了,这样狗就跑了,变成流浪狗了,就像Java中的对象被当做垃圾回收了一样:


接着再来看一下交叉引用的例子:



如果JVM采用的是引用计数法,那么狗2原先被dog2和dog1.son两个变量引用这,执行完dog2 = null之后,还被dog1.son引用,狗2是不会被回收的。 


但是如果使用可达性分析法,我们就会发现,这两只狗和这个世界已经没有关联了,尽管他们俩还是父子关系,JVM对于这种互相引用,但是和GC ROOTS已经没有关联的对象,照样会进行回收。


引用传递的替代方法


引用传递有两个好处:


引用传递可以避免调用方法时进行拷贝,尤其是当方法的入参是个大对象时,拷贝会耗费大量的时间和空间,当然,这一点Java已经巧妙地解决了,因为对于对象,拷贝的只是它的引用而已;


引用传递可以对外面的对象进行修改,这也是很多语言支持引用传递的原因。


那么,在Java,要怎么实现“对外面的对象进行修改”类似的功能呢? 


答案是使用返回值,类似这样:



当然,如果你只是对一个对象进行修改,然后返回这个对象的新的版本,那么可以考虑把这个方法挪到这个对象里面去,就像这样:



还有,如果你是需要返回多个值,不使用引用传递,要如何实现? 


答案是返回一个对象,比如你想修改一个地方的经度和纬度,那么与其传入log和lat两个变量,不如把他们封装到Point对象里面去。


以上,希望对你有所帮助。


来源:程序人生


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

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

相关文章

gif分解工具_Python之GIF图倒放,沙雕快乐源泉

GIF图现在已经融入了我们的日常网络生活,微信群、QQ群、朋友圈......一言不合就斗图,你怕了吗?不用担心,只要学会了Python之GIF倒放技能,你就是“斗图王”。咱们直接开始本文的内容!使用的工具1PIL(Python …

微软亚洲研究院全球院友线上欢聚,共话新春

金鼠辞旧岁,金牛报春时;万象正更新,乾坤喜气多。西雅图时间 2 月 6 日,北京时间 2 月 7 日,由微软亚洲研究院院友会西雅图分会主办的“牛转新运”院友新春线上茶话会圆满落幕。重量级嘉宾沈向洋、洪小文、张亚勤、张宏…

从串行线程封闭到对象池、线程池

今天讲一个牛逼而实用的概念,串行线程封闭。对象池是串行线程封闭的典型应用场景;线程池糅合了对象池技术,但核心实现不依赖于对象池,很容易产生误会。 本文从串行线程封闭和对象池入手,最后通过源码分析线程池的核心原…

netty springmvc_springmvc源码架构解析之HandlerMapping

说在前面前期回顾sharding-jdbc源码解析 更新完毕spring源码解析 更新完毕spring-mvc源码解析 更新完毕spring-tx源码解析 更新完毕spring-boot源码解析 更新完毕rocketmq源码解析 更新完毕dubbbo源码解析 更新完毕netty源码解析 更新完毕spring源码架构更新完毕springmvc源码架…

腾讯牛逼,我酸了!!

阅读本文大概需要8分钟。腾讯这两天搞了个业内爆炸沸腾的事情:全员阳光普照发放100股,解禁期一年。腾讯股价近年来一直在疯狂上涨,100股折合人民币6万多:关键是员工什么都没做,直接拿到价值6万的股票。作用可以说是相当…

这本造价500万的“黑科技”日历,用377张爆美插画给你365天理想生活

以前,每个人家里, 都挂着一本日历。 爷爷戴着老花镜, 盘看着黄道吉日; 奶奶一字一句, 念叨着每日禁忌; 我们跟着日历过日子, 时光缓慢,记忆清晰。 那时候,日历本上的日子…

eladmin代码自动生成_如何让Mybatis自动生成代码

点击上方“Java知音”,选择“置顶公众号”技术文章第一时间送达!作者:阿进的写字台cnblogs.com/homejim/p/9782403.html在使用 mybatis 过程中, 当手写 JavaBean 和 XML 写的越来越多的时候, 就越来越容易出错。这种重…

.NET微服务

前文传送门:什么是云原生?现代云原生设计理念Microservices微服务是一种构建现代应用程序的流行的体系结构,云原生系统拥抱微服务。微服务是由一组(使用共享结构交互的、独立的小块服务)搭建的分布式集,具有以下特征:在…

还是找程序员做老公,最靠谱!

很多MM在选老公的时候,都会选择帅气多金,职业又稳定的男生做老公,像医生啊、律师啊、老师啊这类职业。 但是,你有没有想过? 医生的身边都围着好多护士小姐,而且天天加班是常态,相处的时间太少&a…

14个超级牛X的免费开源小工具!

最近整理了一些在用的,感觉还不错的开源小工具,有的仅适用MacOS,但多数跨平台。 Homebrew Homebrew — The missing package manager for macOS:https://brew.sh,Mac上非常好用的包管理工具,很多常见的安装…

硬件加速下webview切换闪屏_网页渲染性能优化 —— 性能优化下

博客 有更多精品文章哟。Composite 的优化 终于,我们到了像素管道的末尾。对于这一部分的优化策略,我们可以从为什么需要 Composited Layer(Graphics Layer)来入手。这个问题我们在构建 Graphics Layer Tree 的时候,已…

计算机和网络邻居都不见 了,网上邻居看不到自己和别人电脑怎么办

不少网友都试过,在局域网里面,打开网上邻居,结果里面一台电脑都没有,或者只能看到自己的,看不到其他人的,这是怎么回事呢?学习啦小编在这里教大家如何解决这个问题,希望能帮到大家。…

Python 开发者的 6 个必备库

无论你是正在使用 Python 进行快速开发,还是在为 Python 桌面应用制作原生 UI ,或者是在优化现有的 Python 代码,以下这些 Python 项目都是应该使用的。 Python 凭借其易用的特点,已经被工业界和学术界广泛采用。另一方面&#x…

如何在注册表里计算机用户名,可以通过注册表修改电脑的密码 ?怎么做的?

可以通过注册表修改电脑的密码 ?怎么做的?以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!可以通过注册表修改电脑的密码 ?怎么做的?不用怎么麻烦的运行输入cmd在这里输入 user 用户名 密…

c++游戏代码大全_还在学少儿编程?不如来玩工厂编程师,免费学编程逻辑的小游戏...

40000游戏爱好者已加入我们!每天推荐好玩游戏!加入我们,沐沐带你发现好游戏!《工厂编程师》游戏小程序好玩吗?《工厂编程师》小游戏怎么玩?只有你想不到,没有我找不到的好游戏!「良心…

Istio 1.9 发布——重点改善 Istio 的 Day2 操作

本文译自 Istio 官方博客,原文地址:https://istio.io/latest/news/releases/1.9.x/announcing-1.9/Istio 1.9 版本的重点是改善用户在生产中运行 Istio 的 Day2 操作。在用户体验工作组收集到的反馈意见的基础上,我们希望改善用户的稳定性和整…

Windows漏洞利用开发——利用ROP绕过DEP保护

实验6 Windows漏洞利用开发 6.1实验名称 Windows漏洞利用开发 6.2实验目的 学习windows漏洞利用开发,使用kali linux相关工具对windows内目标程序进行漏洞利用 6.3实验步骤及内容 第三阶段:利用ROP绕过DEP保护 了解DEP保护理解构造ROP链从而绕过DEP…

技术人必备的碎片化时间学习工具

工作、生活节奏超快的今天,想要不断提升自我,碎片化阅读学习是你最佳的选择,如果你有一颗学习的心,那这些学习型的公众号,绝对会让你受益匪浅。 小编为你精选了技术领域几个精品微信订阅号,涵盖了时下最热门…

微型计算机键盘上的shift键 汉语译为,PC计算机键盘上的Shift键称为什么键

满意答案shuzhongle2014.02.25采纳率:56% 等级:12已帮助:7306人朋友,下面是我的答案,希望可以帮得到你!Shift键:上档转换键,也可用于中英文转换。当然Shift键并不仅仅只是这些作用,下面介绍下…

华为的型号命名规则_华为最实惠5G手机来了!畅享Z 5G宣布:5月24日发

5月18日消息,华为宣布畅享系列首款5G手机畅享Z 5G将于5月24日发布。畅享Z系列的到来将使华为在千元市场实现5G覆盖,这也将成为华为价格最低的5G手机系列,值得期待。目前关于畅享Z的细节还很少,有消息称代号为Teller的5G新机隶属于…