2019-03-08 hashset

*** HashMapkey 必须使用不可变类型的对象***

补救:如果用了可变对象,HashSet
boolean contains(Object obj) 就不能用了,可能会达不到想要的效果
boolean remove(Object obj) 可以使用Collectiondefault boolean removeIf(Predicate filter)来处理,本质 iterator.remove()


今天用 HashSet 保存对象的时候出现了问题。事情是这样的,

    @Data
    @AllArgsConstructor
    class Node{
        int x;
        int y;
    }
    @Test
    void name() {
        HashSet 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 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相关的尽量用不可变类型的对象

你可能感兴趣的:(2019-03-08 hashset)