Java永远不会通过引用传递,对吗?…对吗?

Java永远不会通过引用传递,对吗?…对吗?,java,pass-by-reference,pass-by-value,Java,Pass By Reference,Pass By Value,可能重复: 今天我发现了一个不同寻常的Java方法: private void addShortenedName(ArrayList<String> voiceSetList, String vsName) { if (null == vsName) vsName = ""; else vsName = vsName.trim(); String shortenedVoiceSetName = vsName.substrin

可能重复:

今天我发现了一个不同寻常的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);
     }
}
private void addShortenedName(ArrayList voiceSetList,字符串vsName)
{
if(null==vsName)
vsName=“”;
其他的
vsName=vsName.trim();
字符串shortenedVoiceSetName=vsName.substring(0,Math.min(8,vsName.length());
//SCR10638-防止导出空行。
if(shortenedVoiceSetName.length()>0)
{
如果(!voiceSetList.contains(“#”+shortenedVoiceSetName))
voiceSetList。添加(“#”+shortenedVoiceSetName);
}
}

根据我读到的关于Java传递变量、复杂对象或不传递变量的行为的所有信息,这段代码应该什么都不做。那么…我是不是错过了什么?是否有一些细微之处我没有注意到,或者这段代码属于DailyWTF?

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

好吧,它可以操作
数组列表
-这是一个对象。。。如果正在传递对象引用(甚至按值传递),则对该对象的更改将反映到调用方。这就是问题所在吗?

正如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
}

Edit:在这种情况下,这意味着尽管
voiceSetList
可能会由于该方法而发生更改(可能会添加一个新元素),但对
vsName
的更改在该方法之外将不可见。为了避免混淆,我经常标记我的方法参数
final
,这可以防止它们在方法内部被重新分配(意外或非意外)。这将使第二个示例根本无法编译。

我想您可能会感到困惑,因为vsName被修改了。但在此上下文中,它只是一个局部变量,与shortenedVoiceSetName处于完全相同的级别。

引用本身是按值传递的

来自Java How to Program,Deitel和Deitel的第四版:(第329页)

与其他语言不同,Java不允许程序员选择是否通过 每个参数都是通过值或引用。始终传递基本数据类型变量 按价值计算。对象不传递给方法;而是将对对象的引用传递给 方法。引用本身通过值传递—传递引用的副本 使用一种方法。当方法接收到对对象的引用时,该方法可以操纵 直接将对象删除

在大学学习Java时使用了这本书。精彩的参考资料

这里有一篇很好的文章解释它。
我不清楚代码中的确切问题是什么。Java是按值传递的,但数组是按引用传递的,因为它们只传递指针而不传递对象!数组由指针组成,而不是真正的对象。这使它们速度非常快,但也使它们很危险。要解决这个问题,您需要克隆它们以获得副本,即使这样,它也只会克隆阵列的第一个维度

有关更多详细信息,请参见我的答案:(另请参见我的其他答案)


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

嘿,编写一个交换两个
int
s:)的函数是的,切换到C#::-pMehrdad:只使用整数而不是int。整数不是不可变的吗?@Carlos Heuberger:是的,但是你可以用一个元素int[]来代替。包装(在整数或数组中)不会创建按引用传递语义。你仍然在传递价值;您只需传递一个指向包装器或数组的指针。Java变量的两个原则:1)变量通过值传递2)所有变量都是引用(或原语)。“为了避免混淆,我经常将方法参数标记为final,这样可以防止它们在方法内部被重新分配(意外或非意外)。”我不相信您,为什么要更改每一个函数,使显式成为已经存在的语言特性?我之所以问这个问题是因为,如果赋值没有修改对象这一点对一个人来说并不明显,那么他就无法真正理解Java。@Longpoke:我不是唯一一个阅读我的代码的人,所以我是否理解它并不重要。我并没有说我改变了每一个函数——尽管如果你使用PMD,我会这么做,每次你没有标记一个参数final时,它都会警告你。它开始让我感到困惑,Java中所有的变量在默认情况下都不是final的@Longpoke——习惯越严格,出错的机会就越少。为什么您不希望尽可能地防止潜在的错误——即使以更显式的代码(例如创建新变量而不是重新分配参数)为“代价”?(我个人不认为在大多数情况下,更明确的代码是一个成本,因此引号)@ Bill K:将参数标记为最终是可以的,如果您想防止将该参数作为局部变量处理。但对我来说,仅仅为了“防止”人们认为局部参数赋值修改了外部引用而将其标记为final是没有意义的;如果他们认为首先他们可能应该先学习Java(或者几乎任何流行的OO语言?)。另外,我同意Java中的限制,因为它有点符合静态类型的原理,我想我现在将把我的参数标记为final:)@Longpoke-我认为真正的困惑点是当阅读方法的人期望参数的值与方法调用开始时的值相同时。。。没有注意到中间的任务。描述得很好。这是我读过的关于这个主题的最简洁、最有帮助的一篇文章。