哪些问题可能源于覆盖 java.util.HashSets contains() 方法?

Which problems can stem from overriding java.util.HashSets contains()-method?

我想用一个HashSet来存储一些对象:

public class StoredObject{
    Type type; //Type is an enum
    //other fields

    Type getType(){return type;}
}

现在,我只想存储相同 Type 中的一个 StoredObject,因此我在 HashSet 的子 class 中覆盖了 contains()

public MySet<E extends StoredObject> extends java.util.HashSet<E>{
    @Override
    public boolean contains(Object o) {
        if(StoredObject.class.isAssignableFrom(o.getClass())) {//if o implements StoredObject
            for(StoredObject s : this) {
                if(s.getType() == ((StoredObject) o).getType()) return true;
            }
        }
        return false
    }
}

在此之前我想用HashSet修改StoredObjectequals()。但是,上面的方法似乎是一种更短且更安全的方法,尤其是在我的情况下,存储的对象都实现了一个接口并且不扩展相同的 class.

现在我的问题是:这个实现安全吗?我试图寻找它可以破坏的东西,但没有找到任何东西。我读到覆盖 equals() 会破坏集合。 另外,这个 subclass 是否违背了 HashSet 的目的,因为它没有将 HashMap 用于 contains()

HashMap<Type,StoredObject> 是合适的集合。​​

如果您覆盖 equals(Object),那么您还必须覆盖 hashCode(让它实现 Comparable 并可能覆盖 toString 也不是一个坏主意)。使用 @Override 注释来确保您拥有正确的参数类型和拼写 - 很容易出错并且难以调试。

会出现什么问题?

  • HashSet中有很多方法需要重写,所以工作量很大。
  • 在 Java 的未来版本中,可能会向 HashSet 添加更多方法 - 您将如何注意这一点?
  • contains 应该是 O(1) 操作(假设哈希码分布良好),但 OP 实现是 O(n)。
  • Set.equals 在另一个 Set 上将报告不正确的结果。

另请注意,StoredObject.class.isAssignableFrom(o.getClass()) 最好写成 o instanceof StoredObject(假设您的 isAssignableFrom 是正确的)。

Is this implementation safe?

绝对不是。 HashSet 上还有其他方法无法正常工作,例如add(),导致集合的大小不正确。

此外,该实现会完全破坏 contains 方法的性能,使其在 O(n) 而不是 [=35] 中变为 运行 =]O(1).

如果您需要 Set 的等式定义不同于 equals()hashCode() 实现的对象自然定义,请使用 TreeSet 并提供自定义 Comparator.

class MySet<E extends StoredObject> extends java.util.TreeSet<E> {
    public MySet() {
        super(Comparator.comparing(StoredObject::getType));
    }
}

我同意 HashMap<Type, StoredObject> 是一个更好的选择,因为它允许您为给定的 Type 获得 StoredObject,否则Set 很难做到。它还允许您检查仅给定 Type 是否存在,而无需为检查创建虚拟 StoredObject 对象。