我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。

什么是解释?


当前回答

Java 编程语言仅通过值的论点,也就是说,您无法从所称方法中更改呼叫方法中的论点值。


但是,当一个对象例子作为论点转移到一种方法时,论点的价值不是对象本身,而是对象的参考。


对于许多人来说,这似乎是通过参考,行为上,它与通过参考有很多共同点,但是,有两个原因,这是不准确的。

第一,改变已转化为一种方法的能力仅适用于对象,而不是原始价值;第二,与对象类型变量相关的实际价值是对象的参考,而不是对象本身。


The following code example illustrates this point:
1 public class PassTest {
2
3   // Methods to change the current values
4   public static void changeInt(int value) {
5     value = 55;
6  }
7   public static void changeObjectRef(MyDate ref) {
8     ref = new MyDate(1, 1, 2000);
9  }
10   public static void changeObjectAttr(MyDate ref) {
11     ref.setDay(4);
12   }
13
14 public static void main(String args[]) {
15     MyDate date;
16     int val;
17
18     // Assign the int
19     val = 11;
20     // Try to change it
21     changeInt(val);
22     // What is the current value?
23     System.out.println("Int value is: " + val);
24
25 // Assign the date
26     date = new MyDate(22, 7, 1964);
27     // Try to change it
28     changeObjectRef(date);
29     // What is the current value?
30 System.out.println("MyDate: " + date);
31
32 // Now change the day attribute
33     // through the object reference
34     changeObjectAttr(date);
35     // What is the current value?
36 System.out.println("MyDate: " + date);
37   }
38 }

This code outputs the following:
java PassTest
Int value is: 11
MyDate: 22-7-1964
MyDate: 4-7-1964
The MyDate object is not changed by the changeObjectRef method;
however, the changeObjectAttr method changes the day attribute of the
MyDate object.

其他回答

参考是常见的值,无论你使用哪种语言。

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

这就是跳板的工作方式。

在每个例子上创建了一个值 - 一个现有值的副本 - 现在是接收方法来处理它. 当你写“Foo”在方法,它是从EAX,或者自动右转,或双右转,过程取决于语言如何工作和 / 或什么类型的Foo独裁。

现在我们把Foo转到方法:

因此,简而言之,在Java本身的术语中,Java是通过价值,在那里价值可以是:无论是真实的价值还是参考的价值。

将变量转换为方法(目标 7.3) 7.3 确定对对象参考和原始值的影响,当它们转换为对参数进行任务或其他修改操作的方法时。

1. import java.awt.Dimension;
2. class ReferenceTest {
3.     public static void main (String [] args) {
4.         Dimension d = new Dimension(5,10);
5.         ReferenceTest rt = new ReferenceTest();
6.         System.out.println("Before modify() d.height = " + d.height);
7.         rt.modify(d);
8.         System.out.println("After modify() d.height = "
9.     }
10.
11.
12.
13.   }
14. }

C:\Java Projects\Reference>java ReferenceTest
Before modify() d.height = 10
dim = 11
After modify() d.height = 11

注意,当第 4 行的尺寸对象转移到修改() 方法时,在该方法中发生的对象的任何变化都会转移到该对象的参考转移。在前面的例子中,参考变量 d 和 dim 都指向相同的对象。

        void bar() {
           Foo f = new Foo();
           doStuff(f);
        }
        void doStuff(Foo g) {
           g.setName("Boo");
           g = new Foo();
        }

class ReferenceTest {
    public static void main (String [] args) {
      int a = 1;
      ReferenceTest rt = new ReferenceTest();
      System.out.println("Before modify() a = " + a);
      rt.modify(a);
      System.out.println("After modify() a = " + a);
    }
    void modify(int number) {
      number = number + 1;
      System.out.println("number = " + number);
    }
}

  Before modify() a = 1
  number = 2
  After modify() a = 1

正如许多人之前提到的那样,Java总是有价值的。

下面是另一个例子,这将帮助你理解差异(经典交换例子):

public class Test {
  public static void main(String[] args) {
    Integer a = new Integer(2);
    Integer b = new Integer(3);
    System.out.println("Before: a = " + a + ", b = " + b);
    swap(a,b);
    System.out.println("After: a = " + a + ", b = " + b);
  }

  public static swap(Integer iA, Integer iB) {
    Integer tmp = iA;
    iA = iB;
    iB = tmp;
  }
}

印刷:

前: a = 2, b = 3 后: a = 2, b = 3

这是因为 iA 和 iB 是新的本地参考变量,具有相同值的过去参考(他们的点到 a 和 b 相应)。因此,试图改变 iA 或 iB 的参考将仅在本地范围内变化,而不是在该方法之外。

我只是注意到你提到我的文章。

了解这一点的关键是,这样的事情

Dog myDog;

它不是狗;它实际上是指向狗。在Java中使用“参考”这个术语是非常误导性的,这引起了大多数混乱。

这意味着,当你有

Dog myDog = new Dog("Rover");
foo(myDog);

您基本上将创建的狗对象的地址转移到 foo 方法。

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

让我们看看发生了什么。

这里是钥匙。

记住 myDog 是指标,而不是真正的狗,答案是 NO. myDog 仍然有值 42;它仍然指向原始狗(但请注意,由于“AAA”线,它的名字现在是“Max” - 仍然是相同的狗; myDog 的值没有改变)。

在 C++、Ada、Pascal 和支持 pass-by-reference 的其他语言中,您实际上可以更改已通过的变量。

void swap(int *x, int *y) {
    int t = *x;
    *x = *y;
    *y = t;
}

int x = 1;
int y = 2;
swap(&x, &y);

该功能将指标传递给数据,并跟随这些指标访问和修改这些数据。

void swap(int[] x, int[] y) {
    int temp = x[0];
    x[0] = y[0];
    y[0] = temp;
}

int[] x = {1};
int[] y = {2};
swap(x, y);

Java 以值传输对象的参考。

因此,如果对参考论点所指出的对象进行任何修改,则将反映在原始对象上。

但是,如果引用论点指向另一个对象,则原始引用将指向原始对象。