53

可能的重复:
Java 是“按引用传递”吗?

今天发现了一个不寻常的Java方法:

private void addShortenedName(ArrayList<String> voiceSetList, String vsName)
{
     if (null == vsName)
       vsName = "";
     else
       vsName = vsName.trim();
     String shortenedVoiceSetName = vsName.substring(0, Math.min(8, vsName.length()));
     //SCR10638 - Prevent export of empty rows.
     if (shortenedVoiceSetName.length() > 0)
     {
       if (!voiceSetList.contains("#" + shortenedVoiceSetName))
         voiceSetList.add("#" + shortenedVoiceSetName);
     }
}

根据我所读到的有关 Java 传递变量、复杂对象与否的行为的所有内容,这段代码应该什么都不做。所以嗯......我在这里错过了什么吗?我是否遗漏了一些微妙之处,或者这段代码是否属于 thedailywtf?

4

6 回答 6

111

正如 Rytmis 所说,Java 按值传递引用。这意味着您可以合法地在方法的参数上调用变异方法,但您不能重新分配它们并期望值传播。

例子:

private void goodChangeDog(Dog dog) {
    dog.setColor(Color.BLACK); // works as expected!
}
private void badChangeDog(Dog dog) {
    dog = new StBernard(); // compiles, but has no effect outside the method
}

编辑:在这种情况下,这意味着虽然voiceSetList 可能会因这种方法而改变(它可能会添加一个新元素),但vsName在方法之外不会看到改变。为了防止混淆,我经常标记我的方法参数final,以防止它们在方法内被重新分配(无论是否意外)。这将使第二个示例根本无法编译。

于 2009-04-27T20:36:51.593 回答
32

Java 通过value 传递引用,因此您获得了引用的副本,但引用的对象是相同的。因此,此方法确实会修改输入列表。

于 2009-04-27T20:32:25.067 回答
4

引用本身是按值传递的。

摘自 Java How to Program,Deitel & Deitel 的第 4 版:(第 329 页)

与其他语言不同,Java 不允许程序员选择是通过值还是通过引用传递每个参数。原始数据类型变量始终按值传递。对象不传递给方法;相反,对对象的引用被传递给方法。引用本身是按值传递的——引用的副本被传递给方法。当方法接收到对象的引用时,该方法可以直接操作该对象。

大学学习Java的时候用过这本书。精彩参考。

这是一篇很好的文章来解释它。 http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

于 2011-11-03T14:46:13.510 回答
2

好吧,它可以操纵ArrayList- 这是一个对象...如果您传递对象引用(甚至通过值传递),对该对象的更改将反映给调用者。是这个问题吗?

于 2009-04-27T20:33:16.157 回答
1

我认为您很困惑,因为 vsName 已修改。但在这种情况下,它只是一个局部变量,与shortenedVoiceSetName 处于完全相同的级别。

于 2009-04-27T20:51:02.200 回答
-3

我不清楚代码中的确切问题是什么。Java 是按值传递的,但数组是按引用传递的,因为它们不传递对象而只传递指针!数组由指针组成,而不是真实对象。这使它们非常快,但也使它们难以处理。要解决这个问题,您需要克隆它们以获取副本,即使这样它也只会克隆数组的第一个维度。

有关更多详细信息,请参见我的回答:在 Java 中,什么是浅拷贝?(另见我的其他答案)

顺便说一句,数组只是指针有一些优点:您可以(ab)将它们用作同步对象!

于 2012-10-20T12:34:50.547 回答