讨论这个问题之前,先看两个例子:
Example1:
public static void main(String[] args) {
int x = 8;
System.out.println("Change before :" + x);
changeValue(x);
System.out.println("Change after :" + x);
}
public static void changeValue(int a) {
a = 9;
}
结果1
Change before :8
Change after :8
Example2:
public class ValueTransferDemo {
public class People {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void changeValue(People p) {
p.setName("li");
}
public static void main(String[] args) {
People a = new ValueTransferDemo().new People();
a.setName("zhang");
System.out.println("Change before :" + a.getName());
changeValue(a);
System.out.println("Change after :" + a.getName());
}
}
结果2
Change before :zhang
Change after :li
上面两个例子中,基本类型的值并没有被改变,然而对于对象而言,它的Name属性值却被改变了,由此,很多人会得出一个错误结论:java中基本类型的传递是值传递,对象的传递是引用传递。然而事实真的是如此吗?
我们回顾一下值传递和引用传递的定义和区别
传值:当方法参数是值传递时,意味着原参数的一个拷贝被传到了参数内部而不是原始参数,所以任何对于该参数的改变都只会影响这个拷贝值。
传引用:当方法参数是引用传递时,意味着原始参数的引用或者说指针被传递到了方法内部,而不是这个原始参数的内容。
总而言之:就是传递的是变量的副本,还是变量本身的问题,对副本而言,函数对它的修改不会影响到本体,而如果传递的是它的本身,那么函数是直接对它修改的
我们知道,在Java中,函数的局部变量存储在栈中,对象是在堆中分配的,那么对象作为变量传递的时候要如何呢,不太可能在堆中再分配一份,因为太耗资源,所以虚拟机就直接把指向该堆内存的指针复制了一份,作为值传递给函数
1.jpg
这时候对*people copy 进行对象本身的方法操作(get set ...)会直接影响对象实例的值
但如果 使用=操作,将它指向另一个对象实例,那么就会去除*people copy和People之间的联系 *peple copy Instance 2 = new People();
2.jpg
这时,*peple copy对象自身的操作改变的就会是 people Instance2 的值
让我们用代码实现:
example3
public class ValueTransferDemo {
public class People {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void changeValue(People p) {
p = new ValueTransferDemo().new People();
p.setName("li");
}
public static void main(String[] args) {
People a = new ValueTransferDemo().new People();
a.setName("zhang");
System.out.println("Change before :" + a.getName());
changeValue(a);
System.out.println("Change after :" + a.getName());
}
}
结果
Change before :zhang
Change after :zhang
如果java中,对象是引用传递,那么name会被改变才对,然而并没有,所以它还是值传递
结论:
Java 中参数传递是值传递