1、基本数据类型(值类型)的值传递
public class Client2 {
public static void main(String[] args) {
/***********测试方法中参数传递的机制*************/
Client2 client2 = new Client2();
int a = 10;
int b = 20;
System.out.println("调用方法前i的值:" + a);
System.out.println("调用方法前j的值:" + b);
client2.fun(i,j);
System.out.println("调用方法后i的值:" + a);
System.out.println("调用方法后j的值:" + b);
}
void fun(int a,int b){
a += 5;
b += 5;
System.out.println("调用方法时a的值:" + a);
System.out.println("调用方法时b的值:" + b);
}
}
控制台打印结果:
调用方法前 a 的值:10
调用方法前 b 的值:20调用方法时 a 的值:15
调用方法时 b 的值:25调用方法后 a 的值:10
调用方法后 b 的值:20调用方法前和调用方法后a和b的值都没有发生变化,但调用方法时a和b的值发生的变化,验证了参数的传递在调用方法的时候,参数会被创造出一个副本,原本的值是不会改变的。
通过内存解析图解释参数在方法中的传递过程
第一步
程序主方法 main()在执行时从上而下首先执行变量声明的两行代码,
int a = 10;
int b = 20;
- 1
- 2
内存空间发生的变化如图所示:
- 首先,在栈内存开辟两个空间分别存放 a 和 b,地址(hashcode)为 null。
- 然后,在常量池存放字面量 10 和 20,并分别生成它们的特有地址 3308 和 3309(这里的地址是随便写的,仅用于举例,真是地址并非如此)。
- 最后,分别将字面量 10 的地址 3308 和字面量 20 的地址 3309 分别赋给 a 和 b,最终在栈区形成 a 以及 a 对应的地址为 3308 和 b 以及 b 对应的地址 3309。
第二步
执行控制台打印输出语句
System.out.println("调用方法前a的值:" + a);
System.out.println("调用方法前b的值:" + b);
- 1
- 2
打印结果:调用方法前 a 的值:10,调用方法前 b 的值:20。
第三步
执行方法fun1(),执行控制台打印输出语句
ceshi.fun1(a,b);
- 1
System.out.println("调用方法时a的值:" + a);
System.out.println("调用方法时b的值:" + b);
- 1
- 2
打印结果:调用方法时 a 的值:15,调用方法时 b 的值:25。
内存空间发生的变化如图所示:
- 首先,调用方法时,生成参数a、b的副本a’、b’同时在栈内存开辟空间存放a’、b’,并将a、b的值地址传递给a’、b’。
- 然后,执行方法体语句 a’ = a’ + 5 和 b’ = b’ + 5即 a’ = 10 + 5 = 15 和 b’ = 20 + 5 = 25,并将新生成的字面量 15 和 25 存放在常量池,同时生成对应地址 3311 和 3312。
- 最后,再将新的地址 3311 和 3312 分别赋给 a’ 和 b’,在栈区形成 a’ 以及 a’ 对应的地址为 3311 和 b’ 以及 b’ 对应的地址 3312。
第四步
执行控制台打印输出语句
System.out.println("调用方法后a的值:" + a);
System.out.println("调用方法后b的值:" + b);
- 1
- 2
打印结果:调用方法后 a 的值:10,调用方法后 b 的值:20。
2、引用数据类型(类类型)的值传递
public class Client2 {
public static void main(String[] args) {
/***********测试方法中参数传递的机制*************/
Client2 client2 = new Client2();
int a = 10;
int b = 20;
P p = new P();
p.a = 10;
p.b = 20;
System.out.println("调用方法前a的值:" + p.a);
System.out.println("调用方法前b的值:" + p.b);
client2.fun(p);
System.out.println("调用方法后a的值:" + p.a);
System.out.println("调用方法后b的值:" + p.b);
}
void fun(P p) {
p.a += 5;
p.b += 5;
System.out.println("调用方法时a的值:" + p.a);
System.out.println("调用方法时b的值:" + p.b);
}
}
class P {
int i;
int j;
}
控制台打印结果:
调用方法前 a 的值:10
调用方法前 b 的值:20调用方法时 a 的值:15
调用方法时 b 的值:25调用方法后 a 的值:15
调用方法后 b 的值:25
如果方法中传入的是引用数据类型(即类类型),那么传入方法中,如果对对象的相关属性进行了修改,那么原对象的相关属性也会发生改变。
通过内存解析图解释参数在方法中的传递过程
第一步
程序主方法 main()在执行时从上而下首先执行变量声明的两行代码,
int a = 10;
int b = 20;
- 1
- 2
内存空间发生的变化如图所示:
- 首先,在栈内存开辟两个空间分别存放 a 和 b,地址(hashcode)为 null。
- 然后,在常量池存放字面量 10 和 20,并分别生成它们的特有地址 3308 和 3309(这里的地址是随便写的,仅用于举例,真是地址并非如此)。
- 最后,分别将字面量 10 的地址 3308 和字面量 20 的地址 3309 分别赋给 a 和 b,最终在栈区形成 a 以及 a 对应的地址为 3308 和 b 以及 b 对应的地址 3309
第二步
执行控制台打印输出语句
System.out.println("调用方法前a的值:" + a);
System.out.println("调用方法前b的值:" + b);
- 1
- 2
打印结果:调用方法前 a 的值:10,调用方法前 b 的值:20。
第三步
执行方法fun1(),执行控制台打印输出语句
ceshi.fun1(a,b);
- 1
System.out.println("调用方法时a的值:" + a);
System.out.println("调用方法时b的值:" + b);
- 1
- 2
打印结果:调用方法时 a 的值:15,调用方法时 b 的值:25。
内存空间发生的变化:
- 首先,调用方法时,参数a、b在堆内存开辟空间存放a、b的值,并将a、b在堆区的值地址传递给栈区中的a、b。
- 然后,执行方法体语句 a = a + 5 和 b = b + 5即 a = 10 + 5 = 15 和 b = 20 + 5 = 25,并将新生成的字面量 15 和 25 替换堆区中原来a、b的值。
- 栈区中a、b指向堆区中a、b的值的地址不变,最后输出a、b的值时,a、b的值为已经被替换的值,即a=15,b=25。
第四步
执行控制台打印输出语句
System.out.println("调用方法后a的值:" + a);
System.out.println("调用方法后b的值:" + b);
- 1
- 2
打印结果:调用方法后 a 的值:15,调用方法后 b 的值:25。