一、问题抛出
我们先看一下下面的代码
public static void main(String[] args) {
String str = "abc";
System.out.println("方法调用前:"+str);
passParam(str);
System.out.println("方法调用后:"+str);
}
public static void passParam(String str){
str = "abcd";
System.out.println("方法调用"+str);
}
你们觉的最后方法调用后打印的是“abc”还是“abcd”呢?
可能会理所当然觉的肯定是“abcd”,至于理由嘛,很简单,str首先存的是指向“abc”的引用,在passParam()方法中,str指向了“abcd”,所以最后打印的肯定是“abcd”
但是抱歉,答案是“abc”
二、值类型和引用类型
回答上面的问题前,我们先来了解两个基础概念,值类型和引用类型
值类型:对应的就是Java的八种基本类型,比如byte,short,int,long等共八种,它们在栈帧中存储的是一个具体的值,比如1
引用类型:存储的是指向堆中具体某个对象或值的引用地址,比如对象,数组,字符串等
三、值传递和引用传递
弄清楚上面两个概念后,我们再来看看值传递和引用传递
首先说这两个的区别,它们之间最大的区别在于值传递传递的变量的副本,在子方法里修改这个变量,原方法的中的该变量不会受到影响,
引用传递则恰好相反,因为传递的引用地址,所以在子方法在堆中修改了这个对象的具体值,那么原方法的变量根据原来的引用就会发现它的值发送了变化
我们可以先看看这个例子,为了便于阅读,我只贴了关键字段
static class User{
public String name;
public Integer age;
}
public static void main(String[] args) {
User user = new User("张三",21);
System.out.println("方法调用前:"+user);
passParam(user);
System.out.println("方法调用后:"+user);
}
public static void passParam(User user){
user.setName("李四");
System.out.println("方法调用"+user);
}
我相信类似的代码在我们平常的工作中基本都能看到,结果想必大家都很清楚,最后的结果user的name是“李四”
如果根据这个结果的思路代入到最开始的例子,我们发现两者的结果不一样,开始例子中的变量最后并没有被改变,而这里却发生了改变,导致这两者出现差异的原因是什么呢?
答案是Java中只存在值传递,不存在引用传递,或许有人立马就反驳了,你前面说值传递不会影响原来方法的变量,这里明明都变了,还说只存在值传递,这不是自己打自己脸吗?
别急,我们先分析一下在这个例子里main方法到底做了什么。
或许有人依然觉的,如果这里是引用传递,应该也是同样的结果啊,那凭什么你说这里是值传递呢,那么我们就分析开始的例子
如果你还想反驳,那就只能用出杀手锏了,请看下面这个例子
public static void main(String[] args) {
int age = 18;
System.out.println("方法调用前:"+age);
passParam(age);
System.out.println("方法调用后:"+age);
}
public static void passParam(int age){
age = 30;
System.out.println("方法调用"+age);
}
根据前面提到的两者特性,值传递是不会影响原来的值,而引用传递是会改变原来的值,如果最后age = 18那说明是值传递,如果说age=30,那么是引用传递
至于原因嘛,前面已经分析的很清楚了,passParam方法只是修改副本的值,并不会影响原来的值,因此原方法中的变量不会受到影响
四、结论
Java中只存在值传递,不传递引用传递,很多我们觉的是引用传递的原因是原变量和副本变量指向的同一个地址的值发生改变,造成我们觉的字方法里修改变量的值会引起原原变量的变化