【问题标题】:When adding a object to a java collection is it added by value or reference?将对象添加到 java 集合时,它是通过值添加还是引用添加?
【发布时间】:2026-02-08 04:10:01
【问题描述】:

我环顾四周,无法弄清楚这一点:我有一个实现观察者模式的对象和一个允许在列表中的任何对象上触发更改事件时将侦听器添加到列表的实现避免手动添加/删除列表中每个对象的侦听器。

我遇到的问题是,当创建相同 List 实现的新实例并从现有列表中添加对象时,对象更改不会从添加到新列表的 bean 中触发。我的想法是,在将对象添加到 Collection 时,它只会添加指向现有对象的指针,在这种情况下,更改通知将在新列表中的对象上触发,但这并没有发生。谁能帮我弄清楚问题可能是什么?我见过类似的问题,但没有一个可以帮助我解决这个问题。

用例是一个股票扫描仪,其中一个列表包含我正在关注的市场中的所有股票,扫描仪列表仅包含通过标准的股票,但扫描仪没有获取价格、数量等更新使用观察模式触发。 - 邓肯

【问题讨论】:

标签: java pointers collections


【解决方案1】:

始终按价值计算!

对于对象,传递的值是引用的值,而不是它自身的引用。

See most of these links

支持引用传递的语言(Java 不支持)可以执行以下操作:

Foo foo = new Foo();//create a new object
foo.name("Old foo"); // label it
modify( foo ); // try to modify it
// In a language that supports byRef will print "New foo". 
// In Java will print "Old foo" always
println( foo ); 
... 
void modify( Foo foo ) {
   foo = new Foo(); // reference assigned a new different object
   foo.name("New foo");
}

因此,支持通过引用传递的语言会将方法内创建的新对象放入传递给它们的引用(它们毕竟会收到 reference )。像 C++ 和 VB 这样的语言可以做到这一点..

不支持按引用传递的语言(如 Java)不会将新对象分配给原始引用,Java 会将其分配给引用的 副本(在传递的参数 --> void modify( Foo foo ) { ) 但原来的那个,在方法之前创建的那个将保持不变,因此仍然使用Old foo

【讨论】:

  • 恕我直言,说它是“通过引用传递”更有用。当然,引用是一个值,但我发现这个论点是在玩语义。你不妨说“没有对象,只有引用的值”。
  • @Bohemian Objects 确实有出口,但从外面无法到达。而且说“你得到引用的值”是正确的一些其他的编程语言,比如C++,或者VB让你直接修改引用。
  • @Bohemian,虽然我同意你的观点,扩展一点“按价值传递”会提供信息,但我不会直接将其称为“按引用传递”。这意味着 Java 支持一种 void swap(String a, String b),它可以将引用 xy 交换为:String x = "X", y = "Y"; swap(x, y);(这在 Java 中是不可能的,当然!)。
  • @我并不是说你们错了,但显然 OP 是游戏的新手,我不想混淆他。我更愿意回答说“它是通过引用传递”,并声明引用是一个实际上一个值。
【解决方案2】:

你的理解是正确的;集合包含对对象的引用。例如,这个:

final StringBuilder stringBuilder = new StringBuilder();
final List<StringBuilder> stringBuilderList = new ArrayList<StringBuilder>();
stringBuilderList.add(stringBuilder);
stringBuilderList.add(stringBuilder);
stringBuilder.append("yes");
System.out.println(stringBuilderList);

将打印这个:

[yes, yes]

因为只有一个StringBuilder 实例,所以附加的"yes" 在列表的每个元素中。

但请注意,这些集合按值保存这些引用,而不是按引用。例如,这个:

StringBuilder stringBuilder = new StringBuilder("yes");
final List<StringBuilder> stringBuilderList = new ArrayList<StringBuilder>();
stringBuilderList.add(stringBuilder);
stringBuilder = new StringBuilder("no");
// now stringBuilder refers to a different object than before
stringBuilderList.add(stringBuilder);
System.out.println(stringBuilderList);

将打印这个:

[yes, no]

因为列表的两个元素引用了不同的对象,即使两个对象都由同一个变量标识。

要获得更多帮助以找出代码出了什么问题,我认为您必须发布一个演示该问题的最小程序。

【讨论】:

    【解决方案3】:

    Java 对象总是通过引用传递。

    因此,除非您的 Collection 的“add”方法执行其他操作(例如克隆对象或将其用作原型等),否则一切都应该正常工作。

    我认为您的问题更多在于通知的逻辑,而不是集合本身。我建议你粘贴一些代码。

    【讨论】:

    • 查看 OscarRyz 的答案。它是按值传递的,但是,该值是引用的值。
    • 关于通知逻辑的好点,我认为这可能是我的问题的一部分。
    【解决方案4】:

    根据 Java 规范,所有内容在 Java 中都作为值传递。这个SO discussion 有很好的例子说明它是如何工作的。具体阅读第二个答案。

    【讨论】:

      【解决方案5】:

      是的,在 Java 中,每个类(但不是简单类型)都是通过引用传递的。

      如果你的对象支持,你可以使用克隆来解决你的问题。

      【讨论】: