前言
在Java编程中,参数传递有两种方式:值传递和引用传递。这两种传递方式决定了变量在方法内部的变化如何影响原始变量。本文将深入探讨这两种传递方式的概念、应用和注意事项,并且从面试题入手,分栈堆内存的情况。
一、值传递与引用传递
值传递是指在方法调用时将实际参数(原始变量)的副本传递给形式参数。这意味着在方法内部对形式参数的修改不会影响实际参数。值传递在传递基本数据类型(如int、float、double等)和引用数据类型的包装类(如Integer、Float、Double等)时发生。
引用传递是指在方法调用时将实际参数的引用(内存地址)传递给形式参数。这意味着在方法内部对形式参数的修改可能会影响实际参数。引用传递通常发生在对象类型上。
二、面试案例
看一下面试题,看起来就几行代码很简单,那么到时a和b最终结果是什么呢?
运行结果,输出的是AB B,而不是AB,AB
占堆内存分析:
一开始栈中有a和b变量,分别指向堆中的A和B。a->000x1(A),b->000x2 (B)
operator(a, b);操作,新增了方法局部变量x和y,并且也是指向A和B。x->000x1(A),y->000x2 (B)
接下来,x操作append,拼接y,x指向对应的内存值000x1(A)变成了000x1(AB);而y = x,表示的是y指向了x的内存地址。
最终y->x->000x1(AB)。此时,a和b的只想其实都没变化,a还是指向000x1,b还是指向000x2。所以a和b对应的值是
AB和B。
如图最终栈堆内存图:
如果改成这样,就可以看到四个变量最终的值了,跟我们上面分析的结果一样。
代码语言:java复制public class Test {
public static void main(String[] args) {
StringBuffer a = new StringBuffer("A");
StringBuffer b = new StringBuffer("B");
operator(a, b);
System.out.println(a " " b);
}
public static void operator(StringBuffer x, StringBuffer y) {
x.append(y);
y = x;
System.out.println("y:" y " ,x:" x);
}
}
最终结果
总结
这个问题其实涉及到了,变量的范围,x和y只有在operator生效,不会影响到a和b,但是如果operator接受的是对象,则传递的是地址而不是值,如果方法改变地址的内容(比如x.append(y)),外部引用的变量(比如a)获取到的值也会更新。所以方法的参数传递机制,如下规则: (1)形参(形参是在函数定义中声明的参数)是基本数据类型 传递数据值 (2)实参(实参是在函数调用时传递给函数的值)是引用数据类型 传递地址值 特殊的类型:String、数组 包装类等对象不可变性
我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!