参考对象与值参考

时间:2012-02-27 16:00:52

标签: java pass-by-reference pass-by-value

我在这里阅读此评论:Passing a String by Reference in Java?

  

是的,这是一种误解。这是一个巨大而广泛的误解。它   导致我讨厌的面试问题:(" Java如何通过   参数&#34)。我讨厌它,因为大约一半的采访者   实际上似乎想要错误的答案("原始值按值,对象   参考")。正确的答案需要更长时间才能给出,而且似乎也是如此   把他们中的一些混淆了。并且他们不会被说服:我发誓我不及格了   技术屏幕,因为CSMajor型筛选器听说过   大学中的误解并认为它是福音。 FEH。 - CPerkins   8月13日&09; 09:14

有人可以解释一下,新程序员可以理解,说:

之间有什么区别

"在Java中,原语按值传递,对象通过引用传递。"

"在Java中,没有任何内容通过引用传递,引用按值传递。"?

这些陈述在某种意义上都是真的吗?我不想邀请一场咆哮的游行,但这听起来像是一个非常重要的概念,而我还是不完全明白

4 个答案:

答案 0 :(得分:12)

我认为误解在于变量不能包含对象这一事实。如果你掌握了这一点,那么显然变量只能包含对象(或原始值)的引用。从那里开始实现引用按值传递的步骤(就像原始值一样)非常小。

您可以通过一个非常简单的测试来确定语言是否支持通过引用传递。问问自己是否可以使用该语言编写交换函数,即类似

的函数
x == A, y == B

swap(x, y);

x == B, y == A

作为一名Java程序员,您很快就会意识到无法在Java中实现这一点,因此您(正确地)得出Java 没有通过引用传递的结论

回到你的句子:

  • 在Java中,原语按值传递,对象通过引用传递。

这是 false 。我认为你只能传递变量中包含的东西,正如我上面所说,变量不能包含一个对象,因此你无法在Java中传递一个对象。

  • 在Java中,没有任何内容通过引用传递,引用按值传递。

true

答案 1 :(得分:7)

这样的事情在绘制时总是更容易。考虑以下两个变量,一个是基本类型,另一个是引用类型:

    int i    = 5;
    String s = "test";

在内存的某个地方,有i的条目如下所示:

  i
-----
| 5 |
-----

类似地,内存中还有s条目,但引用到堆上的某个位置,因为s是引用类型变量,对象存储在堆:

                            ----------- 
 s                 |------->|  "test" |
-----              |        |---------|
| --|--------------|        |         |
-----                       |         |
                            |         |
                            |---------|

因此s的值是对堆上的String对象的引用,因此如果将s传递给方法:

printString(s);

public void printString(String arg)
{
   System.out.println(arg);
}

实际复制到arg参数中的值是对堆上s的引用:

                            ----------- 
 s                 |------->|  "test" |<-----|
-----              |        |---------|      |
| --|--------------|        |         |      |
-----                       |         |      |
                            |         |      |
                            |---------|      |
 arg                                         |
-----                                        |
| --|----------------------------------------- 
-----

希望这有帮助。

答案 2 :(得分:6)

好问题。请考虑以下示例

void foo(Object obj) {
  obj = new Foo(); 
}
Object o = new Bar();
foo(o);
// is o Foo or Bar?
  • 如果pass by-reference o引用在调用foo
  • 之后可能已更改
  • 如果pass by-reference-by-value引用o调用foo
  • 之后未更改

答案 3 :(得分:2)

两个语句互斥,第一个语句为false。在Java中,一切都是通过值传递的,甚至是对象的引用。混淆源于这样一个事实:当一个对象通过值传递时,它是其引用的副本传递的内容,并且如果该对象是可变的并且在方法内被修改,则可以从外面的地方叫它。

让我用几个例子来解释一下。在这种情况下,x是按值传递的基本类型:

void m(int x) {
    x = 10;
}
// in some other place, the above method gets called
x = 5;
m(x);
// in here, x's value is still 5

在这种情况下,x是一个对象类型,其引用的副本按值传递:

void m(ArrayList<Integer> x) {
    x.add(10);
}
// in some other place, the above method gets called
ArrayList<Integer> x = new ArrayList<Integer>();
x.add(5);
m(x);
// in here, x contains [5, 10]