Java 创建扩展哈希集/继承的计数类 如果我们考虑以下类来计算哈希集中添加的对象: public class CountingHashSet<E> extends HashSet<E> { public int addCount = 0; @Override public boolean add(E e) { addCount +=1; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } 公共类CountingHashSet扩展HashSet{ 公共整数addCount=0; @凌驾 公共布尔加法(E){ addCount+=1; 返回super.add(e); } @凌驾 公共布尔加法(Collection

Java 创建扩展哈希集/继承的计数类 如果我们考虑以下类来计算哈希集中添加的对象: public class CountingHashSet<E> extends HashSet<E> { public int addCount = 0; @Override public boolean add(E e) { addCount +=1; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } 公共类CountingHashSet扩展HashSet{ 公共整数addCount=0; @凌驾 公共布尔加法(E){ addCount+=1; 返回super.add(e); } @凌驾 公共布尔加法(Collection,java,collections,hashset,Java,Collections,Hashset,这就是多态性的工作原理。您的对象属于类型CountingHashSet,因此调用add将调用CountingHashSet.add,即使是从超类型也是如此。这就是多态性的工作原理。您的对象属于类型CountingHashSet,因此对add的调用将调用CountingHashSet.add,即使是从超类型添加。您将继承视为组合。事实并非如此。调用不会在HashSet上结束为“add()”—它们最终在当前对象上结束为“add()” 但是为什么super.addAll(c)调用我重新定义的add方法

这就是多态性的工作原理。您的对象属于类型
CountingHashSet
,因此调用
add
将调用
CountingHashSet.add
,即使是从超类型也是如此。

这就是多态性的工作原理。您的对象属于类型
CountingHashSet
,因此对
add
的调用将调用
CountingHashSet.add
,即使是从超类型添加。

您将继承视为组合。事实并非如此。调用不会在
HashSet
上结束为“
add()
”—它们最终在当前对象上结束为“
add()

但是为什么super.addAll(c)调用我重新定义的add方法呢

因为这就是虚拟方法的行为。
addAll
只调用
add()
,它将使用实际类型中最重写的实现。多态性总是这样工作的。让我们编写一个简单的示例:

class Superclass {
    public void foo() {
        bar();
    }

    public void bar() {
        System.out.println("Superclass.bar()");
    }
}

class Subclass extends Superclass {
    @Override
    public void bar() {
        System.out.println("Subclass.bar()");
    }
}

public class Test {

    public static void main(String [] args) {
        Superclass x = new Subclass();
        x.foo(); // Prints Subclass.bar()
    }
}

Subclass.bar()
的结果是否与您在本例中所期望的结果相同?如果是,您希望您的版本会有什么不同?仅仅因为您正在调用
super.addAll()
并不意味着对象突然处于“非重写”状态模式或诸如此类的方式。

您将继承视为组合。事实并非如此。调用不会以“
哈希集上的
add()
”结束,而是以“
当前对象上的add()
”结束

但是为什么super.addAll(c)调用我重新定义的add方法呢

因为这就是虚拟方法的行为。
addAll
只调用
add()
,它将使用实际类型中最重写的实现。多态性总是这样工作的。让我们编写一个简单的示例:

class Superclass {
    public void foo() {
        bar();
    }

    public void bar() {
        System.out.println("Superclass.bar()");
    }
}

class Subclass extends Superclass {
    @Override
    public void bar() {
        System.out.println("Subclass.bar()");
    }
}

public class Test {

    public static void main(String [] args) {
        Superclass x = new Subclass();
        x.foo(); // Prints Subclass.bar()
    }
}

Subclass.bar()
的结果是否与您在本例中所期望的结果相同?如果是,您希望您的版本会有什么不同?仅仅因为您正在调用
super.addAll()
并不意味着对象突然处于“非重写”状态模式或类似的模式。

好的,现在更清楚了。但是
addAll
使用
add
的事实是类的内部实现的细节,它不会从外部产生任何影响。因此,我认为这表明继承可能是一个问题,对吗?(它破坏了封装)@user2336315:好吧,它在
AbstractCollection
中有文档记录。但是,是的,继承使原本纯粹是实现细节的东西泄漏到文档化API中的方式,在IMO中肯定是继承的问题,这也是我喜欢组合的原因之一:)这正是高效Java用来说明为什么组合比继承更可取的例子,一直到变量名。@LouisWasserman我在类中看到了这一点,我不知道它在书中,现在更清楚了。
addAll
使用
add
是类的内部实现的一个细节,它将因此,我认为这表明了继承可能是一个问题,对吗?(它破坏了封装)@user2336315:好吧,它在
AbstractCollection
中有文档记录。但是,是的,继承使原本纯粹是实现细节的东西泄漏到文档化API中的方式,在IMO中肯定是继承的问题,这也是我喜欢组合的原因之一:)这正是高效Java用来说明为什么组合比继承更可取的例子,一直到变量名。@LouisWasserman我在课堂上看到过这个,我不知道它在一本书中
class Superclass {
    public void foo() {
        bar();
    }

    public void bar() {
        System.out.println("Superclass.bar()");
    }
}

class Subclass extends Superclass {
    @Override
    public void bar() {
        System.out.println("Subclass.bar()");
    }
}

public class Test {

    public static void main(String [] args) {
        Superclass x = new Subclass();
        x.foo(); // Prints Subclass.bar()
    }
}