Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

勿在流沙筑高台,出来混迟早要还的。做一个积极的人编码、改bug、提升自己我有一个乐园,面向编程,春暖花开!本文导图:一、由一个提问引发的思考在Stack Overflow 看到这样一个问题:Is Java “pass-by-reference” or “pass-by-value”?翻译成中文:Java是传值还是传引用?请先不要看下面的内容,思考10秒后,在继续阅…

大家好,又见面了,我是全栈君。

做一个积极的人

编码、改bug、提升自己

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

推荐阅读

第一季

0、Java的线程安全、单例模式、JVM内存结构等知识梳理
1、Java内存管理-程序运行过程(一)
2、Java内存管理-初始JVM和JVM启动流程(二)
3、Java内存管理-JVM内存模型以及JDK7和JDK8内存模型对比总结(三)
4、Java内存管理-掌握虚拟机类加载机制(四)
5、Java内存管理-掌握虚拟机类加载器(五)
6、Java内存管理-类加载器的核心源码和设计模式(六)
7、Java内存管理-掌握自定义类加载器的实现(七)
第一季总结:由浅入深JAVA内存管理 Core Story

第二季

8、Java内存管理-愚人节new一个对象送给你(八)
【福利】JVM系列学习资源无套路赠送
9、Java内存管理-”一文掌握虚拟机创建对象的秘密”(九)
10、Java内存管理-你真的理解Java中的数据类型吗(十)
11、Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)
12、Java内存管理-探索Java中字符串String(十二)

实战

一文学会Java死锁和CPU 100% 问题的排查技巧

分享一位老师的人工智能教程。零基础!通俗易懂!风趣幽默!
大家可以看看是否对自己有帮助,点击这里查看【人工智能教程】。接下来进入正文。

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

本文导图:

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

分享一位老师的人工智能教程。零基础!通俗易懂!风趣幽默!
大家可以看看是否对自己有帮助,点击这里查看【人工智能教程】。接下来进入正文。

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

Stack Overflow 看到这样一个问题:

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

翻译成中文:

Java是传值还是传引用?

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

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

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

}

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)


打印结果如下


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

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

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

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

Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)

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


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!


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



Java编程技术乐园:一个分享编程知识的公众号。跟着老司机一起学习干货技术知识,每天进步一点点,让小的积累,带来大的改变!


扫描关注,后台回复【资源】,获取珍藏干货! 99.9%的伙伴都很喜欢

image.png | center| 747x519


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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/121017.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python爬取美女图片 爬虫基础

    Python爬取美女图片 爬虫基础Python爬取美女图片爬虫基础简述实现思路关键代码文件下载爬虫代码成果简述作为一个考研狗,每天除了日复一日的复习外,偶尔也想给自己寻找一些生活的小乐趣,今天突然想到了自己曾经稍微接触的爬虫,想看看可以爬取些图片放到电脑上,就花了些时间改了改之前的爬虫代码,爬取了一部分照片先量一下战绩吧。照片不多但也算是自己的一次爬虫小经验。实现思路爬虫的网页很简单,照片真实路径都在页面中直接可以拿到主要流程就是先进入照片浏览的主页,每个照片的主页都会链接几个照片页面,像下面这样,每个图片都会链接一个网页

    2022年6月26日
    25
  • 等价类划分法测试用例设计举例「建议收藏」

    等价类划分法测试用例设计举例「建议收藏」一、基本概念等价类是指程序输入域的子集。等价类划分(EquivalancePartitioning)测试的思想:将程序的输入域划分为若干个区域(等价类),并在每个等价类中选择一个具有代表性的元素生成测试用例。该方法是常用的黑盒(BlackboxTesting)测试用例(Testcase)设计方法。一)划分等价类1.有效等价类与无效等价类…

    2022年10月18日
    0
  • 小米如何安装magisk和太极阳(纯小白篇)

    小米如何安装magisk和太极阳(纯小白篇)首先说明,我本人也是一个小白,很多专业术语和知识都不是特别了解。所以如果教程里有些许错误请见谅。我自己的手机是MI8,MIUI10.x.x.,在我安装msgisk的时候看了很多经验贴才下手的最后一次成功,但是网上并没有一篇完全适合小白的帖子,所以我这个小白就站出来了。好了,下面是正文,有关刷magisk的所有软件,下面都会在用到的地方给出。建议动手之前,先通看一遍本文,然后再按照本文操作。然后你会…

    2022年6月4日
    150
  • malloc函数实现原理!

    malloc函数实现原理!任何一个用过或学过C的人对malloc都不会陌生。大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉。但是,许多程序员对malloc背后的事情并不熟悉,许多人甚至把malloc当做操作系统所提供的系统调用或C的关键字。实际上,malloc只是C的标准库中提供的一个普通函数,而且实现malloc的基本思想并不复杂,任何一个对C和操作系统有些许了解的程序员都可以很

    2022年5月31日
    40
  • msyql多个or,and,

    msyql多个or,and,

    2022年3月3日
    39
  • RSA加密算法简介[通俗易懂]

    RSA加密算法简介[通俗易懂]背景RSA加密算法是公钥密码最著名的算法之一,是由MIT三位(RonRivest,AdiShamir,LenAdleman)提出的,也就以三位的名字首字母命名。该算法的理论基础是“大数分解和素数检测“,如果说有一天,大数分解和素数检测的数学理论被证明可以简单解决,那么RSA算法的加密将没有任何意义。有提出说量子计算机的出现可以大大提高RSA的破解效率。下面我们将简单学习RSA加密算法的

    2022年5月3日
    109

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号