当超类型方法调用同时存在于超类型和子类型中的方法时,将调用哪个实例方法

时间:2019-02-20 20:34:32

标签: java inheritance

如果我在这里缺少一些核心Java,请原谅我。

我在HashSet的javadocs中搜索其实现Collection.containsAll()的规范,显然它继承了AbstractCollection的实现,根据JDK 8 source code documentation这个:

public boolean containsAll(Collection<?> c) {
    for (Object e : c)
        if (!contains(e))
            return false;
    return true;
}

我的问题源于以下事实:HashSet不会覆盖containsAll(),但是会覆盖contains()

public boolean contains(Object o) {
    return map.containsKey(o);
}

AbstractCollection同样:

public boolean contains(Object o) {
    Iterator<E> it = iterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return true;
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return true;
    }
    return false;
}

我的理解是,当实例中未明确指定实例成员调用时,JVM将其隐式替换为this.instanceMemberCall(),在这种情况下,它将转换为AbstractCollection的{​​{1} }被调用。但是,再I read herecontains() / HashMap的{​​{1}}的时间复杂度将是O(n),表明HashSet的{​​{1} }(O(1))被调用。希望能清楚了解其背后的实际语义是什么。

2 个答案:

答案 0 :(得分:3)

不,这仅仅是多态。每当在对象上调用方法时,该对象的 true 类型就无关紧要。

含义:foo()是在Base中实现的。当foo()bar()被Child覆盖时调用bar()时。当您有一个Child对象时,它将始终是被调用的Child bar()版本。

在您的示例中,this不是AbstractSet,而是HashSet

或者换句话说:调用方法的“位置”无关紧要。重要的是调用对象的类型。如前所述,您的对象的类型为HashSet!

答案 1 :(得分:2)

这是一个有趣的问题。 Java中的HashSetHashMap支持。在这种情况下,containsAll()的contains方法中,contains()方法只是在HashSet上循环。这是因为HashSet会覆盖contains和委托。

因为HashSetHashMap支持,所以实际的调用是containsKey(Object key)

HashMap的{​​{1}}主要是给您containsKey(Object key)的复杂性。但是,O(1)确实在containsAll()元素上循环。更糟糕的情况是n

我之所以说它主要是 ,是因为O(n)的性能取决于哈希。