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()
方法并传入red
和blue
变量作为参数时,会创建两个新的对象变量o1
和o2
。o1
和o2
也分别指向内存位置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()
方法内部所发生的一步步的详细过程解析:
- 类在引用内存位置100的
blue
变量上调用changeValue()
方法。第一行创建了一个也指向内存位置100的引用。内存位置100处对象的颜色值被更改为“Red”。 - 第二行创建了一个新对象(颜色值为“Green”)。新对象位于内存位置200。对
balloon
变量执行的任何后续方法都作用于内存位置200处的对象,并且不影响内存位置100处的对象。新的balloon
变量覆盖了第一行创建的引用,并且第一行中的balloon
引用在此方法内部不再可访问。 - 第三行将内存位置200处的新
Balloon
对象的颜色值更改为“Blue”,但不会影响blue
在内存位置100处引用的原始对象。这解释了为什么示例程序输出的最后一行打印“blue color value = Red”,这反映了第一行的更改。
结论
在本篇文章中,您了解了为什么Java是按值传递的。请继续学习更多Java教程来加深您的学习。