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"); // memory reference = 50
Balloon blue = new Balloon("Blue"); // memory reference = 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());
}
// Generic swap method
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
}
}
执行示例程序时,您将获得以下输出:
OutputAfter 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
对象的内存位置。 -
当类
swap()
以red
和变量作为参数调用方法时,将创建blue
两个新的对象变量o1
和。和也分别指向内存位置 50 和 100。o2
o1
o2
-
以下代码片段解释了该
swap()
方法中发生的情况:public static void swap(Object o1, Object o2) { // o1 = 50, o2 = 100 Object temp = o1; // assign the object reference value of o1 to temp: temp = 50, o1 = 50, o2 = 100 o1 = o2; // assign the object reference value of o2 to o1: temp = 50, o1 = 100, o2 = 100 o2 = temp; // assign the object reference value of temp to o2: temp = 50, o1 = 100, o2 = 50 } // method terminated
-
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()
:
-
该类在引用内存位置 100 的变量
changeValue()
上调用方法blue
。第一行创建一个引用,该引用也指向内存位置 100。内存位置 100 处的对象的颜色值更改为"Red"
。 -
第二行创建了一个新对象(颜色值为
"Green"
)。新对象位于内存位置 200。对该balloon
变量执行的任何其他方法都对内存位置 200 处的对象起作用,而不会影响内存位置 100 处的对象。新balloon
变量覆盖了第 1 行中创建的引用,并且balloon
第 1 行中的引用在此方法中不再可访问。 -
第三行将
Balloon
内存位置 200 处的新对象的颜色值更改为"Blue"
,但不影响blue
内存位置 100 处引用的原始对象。这解释了为什么示例程序输出的最后一行会打印blue color value = Red
,这反映了第 1 行的变化。
结论
在本文中,您了解了 Java 为何按值传递。继续学习更多Java 教程。