从我实习面试开始就有在面试中遇到过这个问题:Java是值传递还是引用传递?
当时的我只会背背面试题,但是网上的答案有些还是错的,导致我决心写这一篇文章。
虽然网上已经有很多文章珠玉在前,但是我还是想写一篇我自己的文章,如果写的不好,请见谅
文章开始之前我们还是来解答Java是值传递还是引用传递?
这个问题吧!答案自然是:Java是值传递
给定结论后我们再来解释一下什么叫 值传递&引用传递
-
值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
-
引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
以下图片来自百度百科
上代码证明:
/**
* 证明java值传递demo
*
* @author miao
*/
public class PassValueDemo {
public static void main(String[] args) {
int a = 1;
String str = "1";
User user = new User("阿花", 6);
System.out.println("调用方法前a为:" + a);
System.out.println("调用方法前str为:" + str);
System.out.println("调用方法前user为:" + user);
System.out.println("------------------------------------------");
convert(a, str, user);
System.out.println("------------------------------------------");
System.out.println("调用方法后a为:" + a);
System.out.println("调用方法后str为:" + str);
System.out.println("调用方法后user为:" + user);
}
private static void convert(int a, String str, User user) {
a = 2;
str = "2";
user.setAge(9);
user.setUsername("大壮");
System.out.println("调用方法中a为:" + a);
System.out.println("调用方法中str为:" + str);
System.out.println("调用方法中user为:" + user);
}
}
/**
* @author miao
*/
class User {
public String username;
public int age;
public User(String username, int age) {
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
}
程序的执行结果:
调用方法前a为:1
调用方法前str为:1
调用方法前user为:User{username='阿花', age=6}
------------------------------------------
调用方法中a为:2
调用方法中str为:2
调用方法中user为:User{username='大壮', age=9}
------------------------------------------
调用方法后a为:1
调用方法后str为:1
调用方法后user为:User{username='大壮', age=9}
我们可以看到,身为基本类型的int和被final修饰的String并没有改变,但是引用类型User改变了,所以,网上就有人得出了结论:java针对基本类型是值传递,对于引用类型是引用传递
。但是!!!!这是错误的结论,不相信的话,我在上面的代码中加一行代码,就知道为什么这个是错的结论了
在convert()方法中str = "2";
下面增加一行user = new User("小美", 18)
,让我们看看这样的结果是什么?
程序的执行结果:
调用方法前a为:1
调用方法前str为:1
调用方法前user为:User{username='阿花', age=6}
------------------------------------------
调用方法中a为:2
调用方法中str为:2
调用方法中user为:User{username='大壮', age=9}
------------------------------------------
调用方法后a为:1
调用方法后str为:1
调用方法后user为:User{username='阿花', age=6}
从上述结果可以看出,当我们在 convert
方法中添加 user = new User("小美", 18)
之后,“引用传递”就突然变值传递了?为什么?
这是因为,在 Java 语言中本质上只有值传递,也就说 Java 的传参只会传递它的副本,并不会传递参数本身。
即传入convert()时的user为 User user
的副本,指向同一个new User("阿花", 6)
的堆地址,
当执行user = new User("小美", 18)
时,指向的堆内存改变了,所以再进行任何操作都跟之前的堆地址没关系了,即证实了,传递的是一个副本。
未执行user = new User("小美", 18)
之前
执行user = new User("小美", 18)
之后
总结:通过本文的内容,我们可以得出:在 Java 语言中只有值传递,方法传参时只会传递副本信息而非原内容。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据