【问题标题】:Why isn't my Java LinkedHashSet removing an object it contains?为什么我的 Java LinkedHashSet 没有删除它包含的对象?
【发布时间】:2011-10-26 02:08:07
【问题描述】:

我在LinkedHashSet 中有一个对象,它实现了equalshashCodecompareTo(在超类中),但是当我尝试从集合set.remove(obj) 中删除该确切对象时,remove 方法返回@ 987654328@ 并且对象保留在集合中。 LinkedHashSet 的实现是否应该调用其对象的 equals() 方法?因为它没有。这可能是一个java错误吗?我正在运行 1.6.0_25。

【问题讨论】:

  • First rule of programming: It's always your fault 没有看到您的代码,我们无法告诉您您做错了什么。
  • 请在您的网络摄像头前举起一面镜子,以便我看到您的代码。哦,把所有的窗口都倒过来,这样我就不用倒着读了。在这一点上,我......怀疑这是一个 Java 错误。
  • equals()hashCode()的代码贴在这里
  • 测试 equals 在您传递的对象上删除,并且您认为应该首先删除的对象。
  • 如果HashSetequal(),则删除一个元素。 download.oracle.com/javase/6/docs/api/java/util/…

标签: java linkedhashset


【解决方案1】:

我的猜测是您的对象的 hashCode() 实现返回的值与您将对象添加到集合时的值不同。

【讨论】:

  • 这就是我们要求查看代码的原因——还不是真正的答案;)
  • @Dave 好吧,我的推理是 mekazu 说 equals() 没有被调用,如果由于散列变化而没有通过其散列找到对象,则不会调用。跨度>
  • 不是说你错了,说它为时过早 :) 可能只是对象的状态也在改变——谁知道呢。
  • @mekazu 在 Oracle 的 1.6.0_25 LinkedHashSet 中, contains() 和 remove() 最终都将所提供对象的 hashCode() 映射到数组中的索引。哈希值与在那里找到的条目的哈希值进行比较,因为多个哈希值可以映射到同一个索引,如果哈希值相同,则调用 equals 方法。如果您的对象相等,则它们应该返回相同的哈希码,根据 hashCode() 上的 javadocs
  • 在 hashCode() on Object 的 javadoc 中提到了“警告”:“[..] 在同一个对象上多次调用 [..],hashCode 方法必须始终返回相同的整数,[..]"
【解决方案2】:

LinkedHashSet 适合我:

import java.util.*;

public class Test {
    public static void main( String[] args ) {
        LinkedHashSet<String> lhs = new LinkedHashSet<String>();
        String s = "hi";
        lhs.add( s );
        System.out.println( lhs );
        lhs.remove( s );
        System.out.println( lhs );
    }
}

也许您将一个对不同对象的引用传递给 remove 方法?您确定您没有以任何方式更改参考吗?

还要确保 hashCode() 在插入时返回的值与在尝试删除时返回的值相同。

【讨论】:

  • 更可能是 OP 的 equals/hash/compare 代码的问题。
  • 他说他在“那个确切的对象”上调用 remove。所以我认为他的意思是确切的参考(或缺乏参考)。
【解决方案3】:

这是LinkedHashSet 中的错误的可能性非常小。您应该将此视为对您的问题的合理解释。

假设这是您的代码中的一个错误,那么它可能是由多种原因造成的。例如:

  • 您的 equalshashCode 方法返回的对象答案相互矛盾。
  • 您的equalshashCode 方法依赖于可变字段,并且当对象在集合中时这些字段正在更改。 (例如,如果 hashcode 值发生变化,对象很可能在错误的 hash 链上,导致 remove 方法找不到它。)
  • 您已将equals 方法声明为重载,而不是equals(Object) 的覆盖。 (这可以解释为什么你的equals 没有被调用......假设你的断言实际上是正确的。)
  • 您尝试移除的对象(实际上)不是您插入的对象。
  • 其他东西已经移除了该对象。
  • 您正在运行的某个类的不同版本与您正在检查的源代码不匹配。

现在,我知道您已经驳回了其中一些解释。但这可能为时过早。查看您解雇所依据的证据

您可以使用的另一种方法是使用 Java 调试器来取证检查数据结构(例如 LinkedHashSet 的内部结构)并单步执行应该发生删除的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2015-12-10
    相关资源
    最近更新 更多