java是按值调用还是按引用调用
java是按值调用还是按引用调用,
该问题一般是相对函数而言,就是java中的方法参数。
程序设计语言中有关参数传递给函数,两个专业术语
- 按值调用/传递(call by value):是指在调用函数时将实际参数的值复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
- 按引用调用/传递(call by reference):是指在调用函数时将实际参数的地址(c语言中指针)直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
按值调用与引用调用的区别:实参到底有没有被复制一份给形参,能否修改传进来的值(实参),
值传递 | 引用传递 | |
---|---|---|
根本区别 | 会创建副本 | 不创建副本 |
所以 | 函数中无法改变原始对象 | 函数中可以改变原始对象 |
java程序设计语言采用了按值调用,即java中不存在引用调用
也就是方法得到的是所有参数值的一个拷贝,方法并不能修改传递给它的任何参数变量的内容
基本数据类型
public class Test {
private static int x = 10;
public static void main(String[] args) {
System.out.println("before "+x);
change(x);
System.out.println("after "+x);
}
private static void change(int value) {
value = 30;
System.out.println("change "+value);
}
}
输出结果:
before 10
change 30
after 10
分析:
1)value被初始化为x值的一个拷贝(也就是10)
2)value被乘以3后等于30,但注意此时x的值仍为10
3)这个方法结束后,参数变量value不再使用,被回收
结论:当方法参数类型为基本数据类型时,方法不能修改参数
引用数据类型
class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Student value = new Student("zhang");
System.out.println("before " + value.getName());
change(value);
System.out.println("after " + value.getName());
}
private static void change(Student student) {
student.setName("wang");
System.out.println("change " + student.getName());
}
}
运行结果
before zhang
change wang
after wang
分析:
1)student变量初始化为value值的拷贝,是一个对象的引用
2)调用student变量的set方法作用在这个引用对象上,user和student同时引用的User对象内部值被修改
3)方法结束后,student变量不再使用,被释放,而value保持修改值
结论:当传递方法参数类型为引用数据类型时,方法可以修改参数
把实参对象引用的地址当做值传递给了形式参数
如果传递的是地址,看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。
java引用数据类型,拷贝实参(实参是指向堆的引用)的复制,修改复制值指向的堆中数据,
修改的虽然是拷贝数值,但实参拷贝和实参指向同一堆,所以实参指向的堆也被改变了,但改变的并不是实参本身 (指向那个堆)。
进一步证明java 是值传递
通过java引用对象的例子,可能就觉得java同时拥有按值调用和按引用调用,但是java中确实只有按值调用。
例子:
class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Student value = new Student("zhang");
System.out.println("before " + value.getName());
change(value);
System.out.println("after " + value.getName());
}
private static void change(Student student) {
student = new Student("wang");
System.out.println("change " + student.getName());
}
}
输出
before zhang
change wang
after zhang
1)student变量初始化为value值的拷贝,是一个对象的引用
2)student指向新的堆,并设置为 “wang”
3)方法结束后,student变量不再使用,被释放,而value还是原来的
如java果是引用传递,没有拷贝形参,那value也会指向"wang",但并不是,说明拷贝了形参,进一步证明java 是值传递
举个例子
1)值传递:你有一把钥匙,当你的朋友想要去你家的时候,如果你直接
把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如对钥匙加工,更改钥匙能开的门,那么这把钥匙还给你的时候,钥匙开不了以前的门了,只能开新的门。
2)引用传递:你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。
3)Java值传递也能改变堆中数据:但是,不管上面那种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。家中都会受到影响。
https://blog.csdn.net/javazejian/article/details/51192130
https://blog.csdn.net/weixin_44509889/article/details/93347191
https://www.zhihu.com/question/31203609