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
那样将对象本身索引到集合中。你说“永远无法处理这个问题”——但我们就不能在集合中迭代吗?我们可以用这种方式把所有的成员都召集起来,不是吗?