Java按值传递或者按引用传递
这篇文章是关于Java是按值传递还是按引用传递的一个基本问题。尽管是基本问题,但这个问题主要对作为参数传递的对象引起一些混乱。在本文中,我们将通过一些示例来澄清疑问并清楚地理解该主题。
首先,首先要了解这里使用的两个术语:按值传递和按引用传递。
- 按值传递–按值传递将分配给变量的值复制到另一个变量。另一个变量在其范围内使用复制的值,而无需修改原始值。
- 按引用传递–在按引用传递中,原始变量的别名传递给method参数。
Java是价值传递
在Java中,无论传递的是原始数据还是对象数据,无论哪种类型的数据,始终都是按值传递的。原始值很容易理解,但是在涉及对象时却有些混乱。混淆的产生是由于使用了术语,当将对象作为参数传递时,即所谓的对象引用被传递。
现在是时候看一些示例以清楚了解情况了。
将原语作为方法参数传递
public class PassValue { public static void main(String[] args) { PassValue pv = new PassValue(); int num = 7; System.out.println("Value before method call " + num); pv.displayValue(num); System.out.println("Value after method call " + num); } private void displayValue(int num){ // modifying the value num++; System.out.println("Changed value in method " + num); } }
输出:
Value before method call 7 Changed value in method 8 Value after method call 7
在这里,我们可以看到一个整数变量作为参数传递给方法,因为传递的参数的方法值已更改,但这不会影响原始变量。这表明实际变量的值已复制到参数,以便按值传递。
将对象作为方法参数传递
现在是需要一些解释的对象部分。当传递一个对象时,确实传递了对该对象分配的内存的引用,但是与作为引用传递时相比,将该引用作为值传递时存在细微的差异。
当将对象引用作为值传递时,将变量中存储的存储位置复制到method参数。这意味着更改方法中的对象字段将在所有地方反映出来,但是更改引用本身不会更改原始对象的引用。
但是在通过引用传递的情况下,将传递别名,这意味着甚至可以更改引用。
显示对象字段的示例代码可以更改
public class PassValue { private int num; PassValue(int num){ this.num = num; } public static void main(String[] args) { PassValue pv = new PassValue(7); System.out.println("Value of num before method call " + pv.getNum()); pv.displayValue(pv); System.out.println("Value of num after method call " + pv.getNum()); } private void displayValue(PassValue obj){ // Changing field in the passed object obj.setNum(++num); System.out.println("Changed value in method " + obj.getNum()); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } }
输出:
Value of num before method call 7 Changed value in method 8 Value of num after method call 8
在上面的代码中,我们可以看到该对象已传递给displayValue()方法,并且在那里修改了num字段。输出显示该字段也已在调用方法中更改。
该语句PassValue pv = new PassValue(7);创建一个PassValue类的新对象,并将其初始化为变量num的值为7. pv是存储对创建的对象的引用的变量。
当我们在此语句中调用方法时– pv.displayValue(pv);将存储在pv中的对象引用复制到obj参数。 pv和obj共享相同的引用。
如图所示,变量pv和obj共享相同的内存引用,因此,当使用pv object检索num字段时,使用对象obj对num字段所做的更改是可见的。
显示对象引用的示例代码无法更改
public class PassValue { private int num; PassValue(int num){ this.num = num; } public static void main(String[] args) { PassValue pv = new PassValue(7); System.out.println("Value of num before method call " + pv.getNum()); pv.displayValue(pv); System.out.println("Value of num after method call " + pv.getNum()); } private void displayValue(PassValue obj){ // creating new object means reference is changed obj = new PassValue(10); System.out.println("Changed value in method " + obj.getNum()); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } }
输出:
Value of num before method call 7 Changed value in method 10 Value of num after method call 7
在这里,我们可以看到在displayValue()方法中创建了一个新对象并将其分配给obj参数。但这并不会改变pv对象引用,该引用甚至显示了Java通过值传递的对象。