Java 中只有值传递,没有引用传递

基本类型

... ...
//定义了一个改变参数值的函数
public static void changeValue(int x) {
x = x *2;
}
... ...
//调用该函数
int num = 5;
System.out.println(num);
changeValue(num);
System.out.println(num);
... ...


答案显而易见,调用函数 changeValue() 前后 num 的值都没有改变。

由此做一个引子,我用图表描绘一个值传递的过程:

这里写图片描述

num 作为参数传递给 changeValue()方法时,是将内存空间中 num 所指向的那个存储单元中存放的值,即”5”, 传送给了 changeValue() 方法中的 x 变量,而这个 x 变量也在内存空间中分配了一个存储单元,这个时候,就把 num 的值 5 传送给了这个存储单元中。此后,在 changeValue() 方法中对 x 的一切操作都是针对 x 所指向的这个存储单元,与 num 所指向的那个存储单元没有关系了!
自然,在函数调用之后,num 所指向的存储单元的值还是没有发生变化,这就是所谓的“值传递”!
值传递的精髓是:传递的是存储单元中的内容,而非地址或者引用!

对象

同样,先给出一段代码:

... ...
public class person {
public  String name = "Jack";
... ...
}
... ...
public class Test{
//定义一个改变对象属性的方法
public static void changeName(Person p) {
p.name = "Rose";
}
... ...
public static void main(String[] args) {
//定义一个Person对象,person是这个对象的引用
Person person = new Person();
//先显示这个对象的name属性
System.out.println(person.name);
//调用changeName(Person p)方法
changeName(person);
//再显示这个对象的name属性,看是否发生了变化
System.out.println(person.name);
}
}

答案应该大家都心知肚明:
第一次显示:“Jack”
第二次显示:“Rose”

Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用一个副本。指向同一个对象, 对象的内容可以在被调用的方法中改变,但对象的引用 (不是引用的副本) 是永远不会改变的。

为什么这里是“值传递”,而不是“引用传递”?
我还是用图表描绘比较能解释清楚:

这里写图片描述

主函数中 new 了一个对象 Person,实际分配了两个对象:新创建的 Person 类的实体对象(堆内存中),和指向该对象的引用变量 person(栈内存中)。

正如如上图所示,左侧是堆空间,用来分配内存给新创建的实体对象,红色框是新建的 Person 类的实体对象,000012 是该实体对象的起始地址;而右侧是栈空间,用来给引用变量和一些临时变量分配内存,新实体对象的引用 person 就在其中,可以看到它的存储单元的内容是 000012,记录的正是新建 Person 类实体对象的起始地址,也就是说它指向该实体对象。

调用了 changeName()方法,person 作为对象参数传入该方法,但是大家特别注意,它传入的是什么!!!person 引用变量将自己的存储单元的内容传给了 changeName() 方法的 p 变量!也就是将实体对象的地址传给了 p 变量,从此,在 changeName() 方法中对 p 的一切操作都是针对 p 所指向的这个存储单元,与 person 引用变量所指向的那个存储单元再没有关系了!

java 是值传递,但传递的是栈内存中的值!对于基本类型来说,值存储在栈中,所以传递的是其本身的值;对于引用类型,栈中存储的是其引用地址,真实的值存储在堆内存中,传递的是地址引用的值,只要栈中引用的值相同,最终修改的堆地址是同一个,所以最终内容会同步修改。