Java值传递和引用传递(小白必读)
Java 中方法的参数称为形参,向其传递的变量或常量称为实参。
Java 中的所有参数都采用值传递,也就是说,传递的是值的副本。在实参向形参传递值之后,程序如果改变形参的值,不会影响实参的值,同样,改变实参的值也不会影响形参的值。因此,得到的是“实参的复印件,而不是原件”。
此外,向形参传递的实参的值的级别不可以高于形参的值的级别。例如,不可以向方法的 int 型参数传递一个 double 型值,但可以向 double 型参数传递一个 int 型值。
【实例】基本数据类型参数的值传递
因此,副本和原参数都指向同一个“地址”,改变“副本”指向地址的对象的值,意味着原参数指向对象的值也发生了变化,反之亦然。
引用传值过程中的内存模型如下图所示:
图 1 引用传值过程中的内存模型
【实例】引用类型参数的值传递。
Java 中的所有参数都采用值传递,也就是说,传递的是值的副本。在实参向形参传递值之后,程序如果改变形参的值,不会影响实参的值,同样,改变实参的值也不会影响形参的值。因此,得到的是“实参的复印件,而不是原件”。
Java值传递
对于基本数据类型的参数,传递的是值的副本,副本的改变不会影响原件。此外,向形参传递的实参的值的级别不可以高于形参的值的级别。例如,不可以向方法的 int 型参数传递一个 double 型值,但可以向 double 型参数传递一个 int 型值。
【实例】基本数据类型参数的值传递
public class Test { public static void main(String[] args) { int a = 2, b = 3; System.out.println("交换前变量:a=" + a + ", b=" + b); swap(a, b); // 注意:swap方法中的变量交换不会影响main方法中的变量a和b,因为Java是按值传递的 System.out.println("交换后变量:a=" + a + ", b=" + b); } public static void swap(int a, int b) { int temp; temp = a; a = b; b = temp; System.out.println("swap()方法中a的值为:" + a + "; b的值为:" + b); } }运行结果为:
交换前变量:a=2, b=3
swap()方法中a的值为:3; b的值为:2
交换后变量:a=2, b=3
Java引用传递
当参数是引用类型时,传递的也是值的副本,但是引用类型的值指的是数组、对象等的地址,即传递的是实参变量中存储的“引用”,而不是变量引用的实体。因此,副本和原参数都指向同一个“地址”,改变“副本”指向地址的对象的值,意味着原参数指向对象的值也发生了变化,反之亦然。
引用传值过程中的内存模型如下图所示:
图 1 引用传值过程中的内存模型
【实例】引用类型参数的值传递。
// 定义一个油箱类 class PetrolTank { double petrolAmount; // 变量命名应使用驼峰命名法 PetrolTank(double amount) { petrolAmount = amount; } } class Car { void run(PetrolTank tank) { tank.petrolAmount -= 7.5; // 消耗7.5单位的油 } } public class Example3_10 { public static void main(String[] args) { // 创建一个油箱对象,为油量赋初值 PetrolTank myTank = new PetrolTank(50.0); // 显示汽车行驶之前的油量 System.out.println("当前油箱的油量显示:" + myTank.petrolAmount); // 创建一个汽车对象 Car myCar = new Car(); System.out.println("汽车启动,开始消耗油量"); myCar.run(myTank); // 显示行驶后汽车油箱的油量 System.out.println("行驶后汽车油箱的油量显示:" + myTank.petrolAmount); } }运行结果为:
当前油箱的油量显示:50.0
汽车启动,开始消耗油量
行驶后汽车油箱的油量显示:42.5
mycar.run(mytank);
语句后,mytank 引用值传递给 Car 类的成员方法 run() 中的形参 tank,两个对象名具有相同的实体。