这个坑,是时候填上了~
一、背景
这两天,在网上逛的时候,发现了如下的一道面试题,感觉还有蛮有意思的,要是不仔细看还真容易掉到坑里面。第一眼看起来比较绕,所以比较难理解。最终我跳出了这个坑,也想把这个跳坑的经历分享出来。题目如下 , 请问输出的是什么?为什么?
/**
* @author hafiz.zhang
* @description: 一个奇怪的现象
* @date Created in 2018/7/2 22:44.
*/
public class Test {
public static void main(String[] args) {
String ermao = "a";
String bb = addStr(ermao);
System.out.println(ermao);
}
private static String addStr(String ermao) {
ermao = ermao + "b";
return ermao;
}
}
二、结果及原因
毫无疑问,这道题的答案是:a , 你答对了么?在讲解原因之前,让我们想了解一点基础知识吧:
1. 值传递还是引用传递?
其实,Java官方并没有给出值传递还是引用传递的概念。官方将Java参数传递类型分为传递基本类型参数和传递引用类型参数。当参数为基本类型(Java八大基本类型:int、short、float、double、long、boolean、byte、char)的时候,就是传递基本类型参数了,当参数为封装类型(非基本类型,如Integer、Long、Boolean等)的时候,就是传递引用传递参数了。官方文档地址:Java参数传递。
2. Java内存模型中的堆和栈
从Java的底层机制来说,基本类型的变量存放在栈里;封装类型中,对象放在堆里,对象的引用放在栈里。Java在方法传递参数时,是将变量复制一份,然后传入方法体去执行。
3. 答案是a的原因
因为String类型在传递过程中的步骤如下:
- 虚拟机在堆中开辟一块内存,并存值”a”。
- 虚拟机在栈中分配给ermao一个内存,内存中存的是1中的堆地址。
- 虚拟机复制一份ermao,我们就叫ermao’好了,ermao和ermao’在栈中的内存不同,但此时存的值都是1的堆地址。
- 将ermao’传入方法addStr中。
- 方法体在堆中开辟一块新内存,并存值”ab”。
- 方法体将ermao’的值改变,存入5中新的堆内存地址。
- 方法结束,方法外打印ermao,由于ermao存的是1中分配的堆地址,所有打印结果还是”a”。
还不清晰?没关系,那我们直接上个图会不会来得更直观:
4. Java到底有没有引用传递
博友:归去来兮辞 说不是传递引用类型就是引用传递,Java中没有引用传递。但其实Java中并没有定义值传递还是引用传递,非基本类型的参数传递就是传递引用类型参数,但String是个特例,String类型对象的值是不可变的,因为String类是通过final修饰的char[]数组来存放结果的。每次为String类型的变量重新赋值实际上都是新建了一个新的String实例,但是方法外部String类型变量没有指向新的String实例,所以也就不会获取到新的更改。这就导致了传递String类型参数时虽然是传递引用类型参数但是无法通过参数传递的方式改变其变量值。欢迎大家提出不同意见来相互讨论学习哈~三、总结
通过本文我们就理解了Java在方法传参的整个过程。其实还是上面那句比较重要的话Java在方法传递参数时,是将变量复制一份,然后传入方法体去执行。给棒棒哒自己一波掌声👏👏👏,点滴积累,方成大事~
感谢您花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让博主能喝上一杯咖啡,在此谢过了!
如果您觉得阅读本文对您有帮助,请点一下左下角“推荐”按钮,您的将是我最大的写作动力!另外您也可以选择【关注我】,可以很方便找到我!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/hafiz 欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利!
![个人微信公众号](https://files.cnblogs.com/files/hafiz/qrcode_258.bmp)
![博主微信号](https://files.cnblogs.com/files/hafiz/wechat.bmp)