关于参数在方法中传递过程的理解

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。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值