Java参数传递机制深度解析:值传递与引用传递的本质区别

引言

许多Java程序员都对Java是按值传递还是按引用传递存有疑问。本文将总结为什么Java始终是按值传递的原因。

首先,"按值传递(pass by value)" 和 "按引用传递(pass by reference)" 是什么意思?

  • 按值传递(Pass by value):方法参数的值被复制到另一个变量,然后将这个复制的对象传递给方法。方法使用的是这个副本。
  • 按引用传递(Pass by reference):实际参数的一个别名或引用被传递给方法。方法直接访问实际参数。

通常,这些术语的混淆是由于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
	}

}

当您执行示例程序时,您将得到以下输出结果。

输出

这是文章《Java采用按值传递的方式,而不是按引用传递》的第2部分(共2部分)。

执行swap方法后:’red’颜色值 = Red ‘blue’颜色值 = Blue 执行changeValue方法后:’blue’颜色值 = Red

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

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

swap()方法的示例解释

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

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

swap()方法执行时,下面是一步一步的解释:

  • 假设red指向内存位置50,blue指向内存位置100,并且这些是两个Balloon对象的内存位置。
  • 当类调用swap()方法并传入redblue变量作为参数时,会创建两个新的对象变量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
    } // 方法终止
  • o1o2的值被交换了,但由于这些值是redblue内存位置的副本,所以redblue的颜色值没有发生改变。

由于变量包含对对象的引用,所以常常会错误地认为你传递了引用,并且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()方法内部所发生的一步步的详细过程解析:

  • 类在引用内存位置100的blue变量上调用changeValue()方法。第一行创建了一个也指向内存位置100的引用。内存位置100处对象的颜色值被更改为“Red”。
  • 第二行创建了一个新对象(颜色值为“Green”)。新对象位于内存位置200。对balloon变量执行的任何后续方法都作用于内存位置200处的对象,并且不影响内存位置100处的对象。新的balloon变量覆盖了第一行创建的引用,并且第一行中的balloon引用在此方法内部不再可访问。
  • 第三行将内存位置200处的新Balloon对象的颜色值更改为“Blue”,但不会影响blue在内存位置100处引用的原始对象。这解释了为什么示例程序输出的最后一行打印“blue color value = Red”,这反映了第一行的更改。

结论

在本篇文章中,您了解了为什么Java是按值传递的。请继续学习更多Java教程来加深您的学习。

bannerAds