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()
}
}