Java是按值传递,而不是按引用传递

介绍

许多Java程序员都在质疑Java是按值传递还是按引用传递。本文总结了为什么Java始终是按值传递的原因。

首先,按值传递和按引用传递是什么意思呢?

  • 按值传递:方法参数值被复制到另一个变量,然后将复制的对象传递给方法。方法使用复制品。
  • 按引用传递:将实际参数的别名或引用传递给方法。方法访问实际参数。

通常,对这些术语的困惑是由于Java中的“对象引用”概念引起的。从技术上讲,Java始终是按值传递的,因为即使变量可能持有对对象的引用,该对象引用也是表示对象在内存中位置的值。因此,对象引用是按值传递的。

引用数据类型和基本数据类型都是按值传递的。了解有关Java中数据类型的更多信息。

除了理解数据类型,了解Java中的内存分配也很重要,因为引用数据类型和基本数据类型的存储方式不同。

演示按值传递

以下示例演示了在Java中如何传递值。

示例程序使用以下类:

public class Balloon {

	private String color;

	public Balloon() {}
	
	public Balloon(String c) {
		this.color = c;
	}
	
	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}
}

以下示例程序使用了一个通用方法,swap(),它交换了两个变量。另一个方法,changeValue(),尝试更改变量的值。

public class Test {

	public static void main(String[] args) {

		Balloon red = new Balloon("Red"); // 内存引用 = 50
		Balloon blue = new Balloon("Blue"); // 内存引用 = 100
		
		swap(red, blue);
		System.out.println("After the swap method executes:");
		System.out.println("`red` color value = " + red.getColor());
		System.out.println("`blue` color value = " + blue.getColor());
		
		changeValue(blue);
		System.out.println("After the changeValue method executes:");
		System.out.println("`blue` color value = " + blue.getColor());
		
	}

	// 通用交换方法
	public static void swap(Object o1, Object o2){
		Object temp = o1;
		o1 = o2;
		o2 = temp;
	}

	private static void changeValue(Balloon balloon) { // balloon = 100
		balloon.setColor("Red"); // balloon = 100
		balloon = new Balloon("Green"); // balloon = 200
		balloon.setColor("Blue"); // balloon = 200
	}

}

执行示例程序时,您将获得以下输出:

Output
After the swap method executes: 'red' color value = Red 'blue' color value = Blue After the changeValue method executes: 'blue' color value = Red

输出显示swap()方法未交换原始对象的颜色值。这有助于证明Java是按值传递的,因为swap()方法只作用于原始对象引用值的副本。

这个swap()方法的测试可以用于任何编程语言,以检查它是按值传递还是按引用传递。

解释了示例swap()方法

当您使用new运算符创建类的实例时,对象将被创建,并且变量包含对象保存在内存中的位置。

Balloon red = new Balloon("Red");
Balloon blue = new Balloon("Blue");

下面是swap()方法执行时发生的步骤逐步解析:

  • 假设red指向内存位置50,blue指向内存位置100,并且这些是两个Balloon对象的内存位置。

  • 当类使用redblue变量作为参数调用swap()方法时,将创建两个新的对象变量o1o2o1o2同样指向内存位置50和100。

  • 以下的代码片段解释了swap()方法中的操作:

    public static void swap(Object o1, Object o2) { // o1 = 50, o2 = 100
    	Object temp = o1; // 将o1的对象引用值赋给temp:temp = 50, o1 = 50, o2 = 100
    	o1 = o2; // 将o2的对象引用值赋给o1:temp = 50, o1 = 100, o2 = 100
    	o2 = temp; // 将temp的对象引用值赋给o2:temp = 50, o1 = 100, o2 = 50
    } // 方法结束
    
  • o1 和 o2 的值已交换,但由于这些值是对 red 和 blue 内存位置的副本,因此 red 和 blue 的颜色值不会发生变化。

由于变量包含对对象的引用,常见的错误是认为您正在传递引用并且 Java 是按引用传递的。但是,您传递的是引用的副本,因此它是按值传递的。

示例 changeValue() 方法解释

示例程序中的下一个方法更改了由blue变量引用的对象的颜色值:

private static void changeValue(Balloon balloon) { // balloon = 100
	balloon.setColor("Red"); // balloon = 100
	balloon = new Balloon("Green"); // balloon = 200
	balloon.setColor("Blue"); // balloon = 200
}

以下是changeValue()方法中发生的步骤逐步分解:

  • 该类在blue变量上调用changeValue()方法,该变量引用内存位置100。第一行创建了一个引用,也指向内存位置100。内存位置100处对象的颜色值更改为"Red"

  • 第二行创建了一个新对象(颜色值为"Green")。新对象位于内存位置200。在balloon变量上执行的任何进一步方法都会作用于内存位置200处的对象,并且不会影响内存位置100处的对象。新的balloon变量覆盖了第1行中创建的引用,并且第1行中的balloon引用在此方法中不再可访问。

  • 第三行更改了内存位置200处新Balloon对象的颜色值为"蓝色",但不影响由blue在内存位置100引用的原始对象。这解释了为什么示例程序输出的最后一行打印blue color value = Red,这反映了从第1行的变化。

结论

在本文中,您了解了Java为什么是传值调用。继续学习更多的Java教程

Source:
https://www.digitalocean.com/community/tutorials/java-is-pass-by-value-and-not-pass-by-reference