Java按值传递或者按引用传递

时间:2020-01-09 10:34:49  来源:igfitidea点击:

这篇文章是关于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通过值传递的对象。