InstrumentedHashset和overriding add&都加进去

时间:2017-12-04 20:17:58

标签: java inheritance collections

在Effective Java第2版第16项中,作者提供了一个场景,说明"继承中断封装"其中InstrumentedHashSet继承自HashSet并覆盖方法add()addAll()。我的问题是为什么以下替代方案不能很好地解决我们的问题?可能会出现什么样的新问题:

public class InstrumentedHashSet<E> extends HashSet<E> {

    // The number of attempted element insertions
    private int addCount = 0;

    public InstrumentedHashSet() {
    }

    public InstrumentedHashSet(int initCap, float loadFactor) {
         super(initCap, loadFactor);
    }

    @Override public boolean add(E e) {
         addCount++;
         return super.add(e);
    }
    /* only the add method has been overrided
    @Override public boolean addAll(Collection<? extends E> c) {
         addCount += c.size();
         return super.addAll(c);
    }
    */

    public int getAddCount() {
         return addCount;
    }
}

1 个答案:

答案 0 :(得分:2)

如果您删除addAll的覆盖,则InstrumentedHashSet将容易受到addAllHashSet<T>实施方式变化的影响。

目前,JDK implementation leaves the implementation up to its AbstractCollection base class忠实地为每个项目调用add

public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    Iterator<? extends E> e = c.iterator();
    while (e.hasNext()) {
        if (add(e.next())) // <<== This will call your override
            modified = true;
    }
    return modified;
}

但是,可以采用另一种方法:例如,addAll可以尝试通过在addAll方法内一次扩展哈希桶数组来优化插入,而不是反复调用add。这会破坏代码,因为addCount将不再适当维护。

  

[来自评论]什么会促使Oracle中的Java语言设计者改变HashSet<T>实现?难道不会破坏许多使用addAll调用在其实现中添加的预知知识设计的java程序吗?

这正是项目16试图说明的要点。一旦其他人开始从您的班级继承,您就会变得“锁定”在您的计划代码中未明确说明的实施方面,例如需要addAll在每个项目上调用add的方面。实际上,在没有明确确认的情况下,通过“冻结”代码的方面来继承破坏封装。