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

时间:2020-02-23 14:34:29  来源:igfitidea点击:

Java编程语言中最大的困惑之一是java是按值传递还是按引用传递。
我在访谈中经常问这个问题,但仍然看到受访者对此感到困惑。
所以我想写一篇关于它的文章,以消除周围所有的困惑。

首先,我们应该了解按值传递或者按引用传递的含义。

  • 按值传递:将方法参数值复制到另一个变量,然后传递复制的对象,这就是为什么将其称为按值传递的原因。

  • 按引用传递:将实际参数的别名或者引用传递给方法,这就是为什么将其称为按引用传递的原因。

Java始终是按值传递而不是按引用传递,我们可以通过一个简单的示例来证明它。

假设我们有一个如下所示的"气球"类。

package com.theitroad.test;

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;
	}
}

我们有一个简单的程序,带有一个通用方法来交换两个对象,该类如下所示。

package com.theitroad.test;

public class Test {

	public static void main(String[] args) {

		Balloon red = new Balloon("Red"); //memory reference 50
		Balloon blue = new Balloon("Blue"); //memory reference 100
		
		swap(red, blue);
		System.out.println("red color="+red.getColor());
		System.out.println("blue color="+blue.getColor());
		
		foo(blue);
		System.out.println("blue color="+blue.getColor());
		
	}

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

	//Generic swap method
	public static void swap(Object o1, Object o2){
		Object temp = o1;
		o1=o2;
		o2=temp;
	}
}

当我们执行上面的程序时,我们得到以下输出。

red color=Red
blue color=Blue
blue color=Red

如果看一下输出的前两行,很明显交换方法无效。
这是因为Java是按值传递的,此swap()方法测试可与任何编程语言一起使用,以检查它是按值传递还是按引用传递。

让我们逐步分析程序执行情况。

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

当我们使用new运算符创建类的实例时,将创建该实例,并且变量包含保存对象的内存的引用位置。
在我们的示例中,假设"红色"指向50,"蓝色"指向100,这是两个Balloon对象的存储位置。

现在,当我们调用swap()方法时,将创建两个分别指向50和100的新变量o1和o2。

因此,下面的代码片段说明了swap()方法执行中发生的情况。

public static void swap(Object o1, Object o2){ //o1=50, o2=100
	Object temp = o1; //temp=50, o1=50, o2=100
	o1=o2; //temp=50, o1=100, o2=100
	o2=temp; //temp=50, o1=100, o2=50
} //method terminated

请注意,我们正在更改o1和o2的值,但是它们是"红色"和"蓝色"参考位置的副本,因此实际上"红色"和"蓝色"的值以及输出均没有变化。

如果您已经了解了这一点,则可以轻松理解造成混乱的原因。
由于变量只是对对象的引用,因此我们很困惑要传递引用,因此java通过引用传递。
但是,我们正在传递参考的副本,因此它是按值传递的。
我希望它现在消除所有疑问。

现在,让我们分析foo()方法的执行情况。

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

第一行很重要,当我们调用方法时,该方法在对象的引用位置处被调用。
此时,气球指向100,因此其颜色更改为红色。

在下一行中,ballon引用更改为200,并且在存储位置200上的对象上发生了任何其他已执行的方法,并且对存储位置100上的对象没有任何影响。