不是吧?2020年了居然还有人分不清Java参数传递方式?


前言

今天上班后摸鱼知乎的时候,突然发现有人提了一个问题,下面贴图:
在这里插入图片描述
在这里插入图片描述

看到这个问题,我也反思了下,似乎我确实只是知道答案的,但是似乎并没有很有利的证据来证明我的观点,因此,想了想还是开个博客,从更深层次剖析来验证我的观点(ps: 观点有误望勿喷,可以一起学习交流)


一、Java到底是值传递还是引用传递?

我们先来看下这两者的简单的定义:

值传递(pass by value): 指在调用函数时将实际的参数复制一份到函数中,这样在函数中对参数进行修改,不会影响实际参数。

引用传递(pass by value):指调用函数时将实际的参数地址传递到函数中,那么函数对参数进行的修改将会影响实际的参数。

最后总结下两者的区别:

在这里插入图片描述

值传递

代码如下:

	public static void main(String[] args) {
		int num = 0 ;
		String str = "hello";
		fun(num);
		fun(str);
		System.out.println(num);
		System.out.println(str);
		
	}

	/**
	 * @param str
	 */
	private static void fun(String str) {;
		str = "world";
		
	}

	/**
	 * @param num
	 */
	private static void fun(int num) {
		num = 10 ;
		
	}

//最后输出:
//0
//hello

从上面可以看出:函数并未改变任何原始值,由此得出结论,Java是值传递啊!!!

引用传递

看了上面的证据,可能另外一派并不认同,马上扔出下面的证据,代码如下:

	public static void main(String[] args) {
		int num = 0 ;
		String str = "hello";
		User user = new User();
		user.setName("oldtest");
		user.setAge(20);
		fun(num);
		fun(str);
		fun(user);
		System.out.println(num);
		System.out.println(str);
		System.out.println("user name="+user.getName()+",user age="+user.getAge());
		
	}

	/**
	 * @param user
	 */
	private static void fun(User user) {
		user.setName("newtest");
		user.setAge(18);
		
	}

	/**
	 * @param str
	 */
	private static void fun(String str) {;
		str = "world";
		
	}

	/**
	 * @param num
	 */
	private static void fun(int num) {
		num = 10 ;
		
	}
	
	
	
	public class User{
		private String name ;
		private Integer age ;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Integer getAge() {
			return age;
		}
		public void setAge(Integer age) {
			this.age = age;
		}
		
		
	}

//最后输出:
//0
//hello
//user name=newtest,user age=18

上面的user对象可以看出被函数修改了,由此可以得出:Java是引用传递方式

基本类型值传递,引用类型引用传递

上面的两种证据综合起来看,引出第三种结论:当参数是基本类型时,是值传递,当是引用传递时是引用传递,但是String的情况无法自圆其说吧?

值传递(对象内容引用传递)

其派认为:Java传递方式实质还是值传递,代码如下:

	public static void main(String[] args) {
		int num = 0 ;
		String str = "hello";
		User user = new TaskServiceImpl().new User();
		user.setName("oldtest");
		user.setAge(20);
		fun(num);
		fun(str);
		fun(user);
		System.out.println(num);
		System.out.println(str);
		System.out.println("user name="+user.getName()+",user age="+user.getAge());
		
	}

	/**
	 * @param user
	 */
	private static void fun(User user) {
		user = new User();
		user.setName("newtest");
		user.setAge(18);
		
	}

	/**
	 * @param str
	 */
	private static void fun(String str) {;
		str = "world";
		
	}

	/**
	 * @param num
	 */
	private static void fun(int num) {
		num = 10 ;
		
	}
	
	
	
	public class User{
		private String name ;
		private Integer age ;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public Integer getAge() {
			return age;
		}
		public void setAge(Integer age) {
			this.age = age;
		}
		
		
	}
//输出结果:

//0
//hello
//user name=oldtest,user age=20

从上面的输出结果可以看出,假如对象是引用传递,那么user对象预期应该会被修改,但是实际User对象并未被修改,为何会出现这种情况呢?

实际上通过上面的概念我们很清楚,这里实际是把实参引用地址复制了一份给形参,所以上面的参数是值传递,把实参对象引用的地址当作值传递给了形参。

要区别是值传递还是引用传递,看的应该是实参是否被复制了一份给到形参,而不是看对象的内容是否修改;

那么怎么来解释String呢?其实你在函数中修改str的值时,str = “world”;此语句等价与new String(“world”); 随后改变的是形参的内容,并未影响到实际原始对象的内容。

二、图解

1.String图解

在这里插入图片描述

2.对象图解

在这里插入图片描述

总结

最后总结下,Java的参数传递方式实质还是值传递,不过对于对象来说,传递的是引用地址,形参持有的是实际参数的一份地址copy,通过此地址可以修改原始对象数据,但是对象内容的修改与是否引用传递是否无关,要区分是否引用传递,其根本要看是否形参是实参的一份拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值