*** HashMap
的 key
必须使用不可变类型的对象***
补救:如果用了可变对象,HashSet<MutableObject>
,
boolean contains(Object obj)
就不能用了,可能会达不到想要的效果
boolean remove(Object obj)
可以使用Collection
的 default boolean removeIf(Predicate<? super E> filter)
来处理,本质 iterator.remove()
今天用 HashSet 保存对象的时候出现了问题。事情是这样的,
@Data
@AllArgsConstructor
class Node{
int x;
int y;
}
@Test
void name() {
HashSet<Node> hashSet = new HashSet<>();
Node node = new Node(1, 2);
hashSet.add(node);
// 中途改变了属性值
node.setX(2);
// 这个测试是通过的, so 不包含
boolean contains = hashSet.contains(node);
Assertions.assertFalse(contains);
// so remove不掉
boolean remove = hashSet.remove(node);
Assertions.assertFalse(remove);
// 然而,他们是相等的
Assertions.assertEquals(node, hashSet.stream().findFirst().get());
}
Set 常用情况是放一些基本类型包装类和String 等相对没那么复杂的对象的,所以几乎没有遇到这种情况。
看了一下这里的源码,
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
发现 HashMap 在containsKey(Object key)、remove(Object key)时都计算了hash
so Object改变时根据hash找不到原来的Object了
结论:和hash相关的尽量用不可变类型的对象
网友评论