Java 更改HashSet中的值

Java 更改HashSet中的值,java,hashset,Java,Hashset,我读过这个问题: 但是,我不知道如何解决无法更改哈希集中的项并在以后删除它的问题 我有一些示例源代码: public static void main(String[] args) { TestClass testElement = new TestClass("1"); Set<TestClass> set = new HashSet<>(); set.add(testElement); printIt(testElement, set,

我读过这个问题:

但是,我不知道如何解决无法更改哈希集中的项并在以后删除它的问题

我有一些示例源代码:

public static void main(String[] args) {
    TestClass testElement = new TestClass("1");
    Set<TestClass> set = new HashSet<>();
    set.add(testElement);
    printIt(testElement, set, "First Set");
    testElement.setS1("asdf");
    printIt(testElement, set, "Set after changing value");
    set.remove(testElement);
    printIt(testElement, set, "Set after trying to remove value");
    testElement.setS1("1");
    printIt(testElement, set, "Set after changing value back");
    set.remove(testElement);
    printIt(testElement, set, "Set removing value");
}

private static void printIt(TestClass hullo, Set<TestClass> set, String message) {
    System.out.println(message + " (hashCode is " + hullo.hashCode() + "):");
    for (TestClass testClass : set) {
        System.out.println("    " + testClass.toString());
        System.out.println("        HashCode: " + testClass.hashCode());
        System.out.println("        Element is equal: " + hullo.equals(testClass));
    }
}
结果如下:

First Set (hashCode is 80):
    TestClass [s1=1]
        HashCode: 80
        Element is equal: true
Set after changing value (hashCode is 3003475):
    TestClass [s1=asdf]
        HashCode: 3003475
        Element is equal: true
Set after trying to remove value (hashCode is 3003475):
    TestClass [s1=asdf]
        HashCode: 3003475
        Element is equal: true
Set after changing value back (hashCode is 80):
    TestClass [s1=1]
        HashCode: 80
        Element is equal: true
Set removing value (hashCode is 80):
TestClass toRemove = <the same instance, but mutated>;
for (Iterator<TestClass> iter = set.iterator(); iter.hasNext(); ) {
  TestClass item = iter.next();
  if (toRemove.equals(item)) {
    iter.remove();
  }
}

当hashcode发生更改时,我无法从HashSet中删除该值。在中,我理解为什么会这样,但我不知道如何删除更改的值。有这样做的可能性吗?

您正面临这个问题,因为哈希集中的键不是不可变的。如果没有不可变的键,那么一旦修改,就会丢失原始键对象的引用。而且永远也无法处理这个问题,这有时被称为收集中的内存泄漏。因此,如果您使用不可变键,就不会遇到这种情况。

当您将
testElement
添加到哈希集时,它会根据
testElement
的哈希代码选择一个bucket。当您询问
HashSet
是否包含
TestElement
时,它会计算正在查找的对象的哈希代码,并仅在该bucket中搜索

由于您的
hashCode()
基于非final字段,因此哈希代码可以在HashSet的后台更改。因此,HashSet的基本假设完全无效


Testclass
的正确实现将把
s1
字段作为最终字段。

正如您链接到详细信息的问题以及其他人所指出的,您遇到了可变关键问题。我将从以下列表中重新查询:

注意:如果将可变对象用作集合,则必须非常小心 元素。如果 对象的更改方式会影响equals比较,而 对象是集合中的一个元素

正如你所指出的,你明白了。问题是,在这种情况下,如何实际移除对象?无法使用
Set.remove()
,因为您的对象在哈希表中丢失。但是,您可以使用
迭代器来执行此操作。如下所示:

First Set (hashCode is 80):
    TestClass [s1=1]
        HashCode: 80
        Element is equal: true
Set after changing value (hashCode is 3003475):
    TestClass [s1=asdf]
        HashCode: 3003475
        Element is equal: true
Set after trying to remove value (hashCode is 3003475):
    TestClass [s1=asdf]
        HashCode: 3003475
        Element is equal: true
Set after changing value back (hashCode is 80):
    TestClass [s1=1]
        HashCode: 80
        Element is equal: true
Set removing value (hashCode is 80):
TestClass toRemove = <the same instance, but mutated>;
for (Iterator<TestClass> iter = set.iterator(); iter.hasNext(); ) {
  TestClass item = iter.next();
  if (toRemove.equals(item)) {
    iter.remove();
  }
}
TestClass-toRemove=;
for(迭代器iter=set.Iterator();iter.hasNext();){
TestClass item=iter.next();
如果(toRemove.equals(项目)){
iter.remove();
}
}
这种方法依赖于这样一个事实,即标准的
equals()
方法(如您正在使用的)有一个实例检查,并且该检查将返回true


请记住,这不是解决这个问题的正确方法。正确的方法是使用不可变键或“非常小心”,但这是一种从
HashSet

中删除变异对象的方法。请发布hashcode和equals方法好吗?有趣的是,散列集的结果实际上是散列映射的包装器吗?@robjohncox这是因为散列的工作方式。哈希代码用于存储和检索对象。假设您创建了一个key对象,当您将它放入hashmap中时,它的hashcode方法将被调用来计算散列并找到要存储的bucket。当您尝试检索它时,会再次调用hashcode以获取存储密钥的哈希/桶。如果在存储到集合/映射中后更改键对象,则hashcode方法将为该键对象返回不同的哈希值,这与用于存储键的哈希值不同。非常好,但要在HashSet(hashmap)中搜索引用,不仅要使用hashcode,还要使用equalsused@VolodymyrLevytskyi毫无疑问@JunedAhsan我同意您不会像Set方法
contains
remove
那样将对象本身索引到集合中。你说“永远无法处理这个问题”——但我们就不能在集合中迭代吗?我们可以用这种方式把所有的成员都召集起来,不是吗?