Java 如何像Joshua Bloch所描述的那样拥有一个包装器类等于组合?

Java 如何像Joshua Bloch所描述的那样拥有一个包装器类等于组合?,java,inheritance,composition,Java,Inheritance,Composition,我正在读约书亚·布洛赫的书《有效的java》。在“偏好组合而非继承”的第16项中,他给出了一个使用HashSet并查询自创建以来添加了多少元素的示例(不要与当前大小混淆,当删除元素时,当前大小会下降)。他提供了以下代码和getAddCount返回6,我可以理解。这实际上应该返回3。(这是因为HashSet的addAll方法是在add方法之上实现的) import java.util.HashSet; 公共类InstrumentedHashSet扩展了HashSet{ //尝试插入元素的次数 私有

我正在读约书亚·布洛赫的书《有效的java》。在“偏好组合而非继承”的第16项中,他给出了一个使用HashSet并查询自创建以来添加了多少元素的示例(不要与当前大小混淆,当删除元素时,当前大小会下降)。他提供了以下代码和getAddCount返回6,我可以理解。这实际上应该返回3。(这是因为HashSet的addAll方法是在add方法之上实现的)

import java.util.HashSet;
公共类InstrumentedHashSet扩展了HashSet{
//尝试插入元素的次数
私有int addCount=0;
公共指令集hashset(){
}
公共InstrumentedHashSet(int initCap,float loadFactor){
super(初始上限、荷载系数);
}
@凌驾
公共布尔加法(E){
addCount++;
返回super.add(e);
}
@凌驾
公共布尔addAll(集合c){
返回s.containsAll(c);
}
公共布尔addAll(集合c){
返回s.removeAll(c);
}
公共布尔保留(集合c){
返回s.Retainal(c);
}
公共对象[]toArray(){
返回s.toArray();
}
公共T[]toArray(T[]a){
返回s.toArray(a);
}
@凌驾
公共布尔等于(对象o){
返回s.equals(o);
}
@凌驾
公共int hashCode(){
返回s.hashCode();
}
@凌驾
公共字符串toString(){
返回s.toString();
}
}

import java.util.*;
公共类InstrumentedSet扩展ForwardingSet{
私有int addCount=0;
公共仪表集(集合s){
超级(s);
}
@凌驾
公共布尔加法(E){
addCount++;
返回super.add(e);
}
@凌驾
公共布尔addAll(集合In

由于多态性,
addAll()
在内部调用
add()
,它遵从
@Override
add()
的实现

@Override
public boolean add(E e) {
    addCount++;
    return super.add(e);
}
增加计数并打印
6
(3+1+1+1)

并打印
3
。此处对
集s
而不是实例调用
add()

结论是,如果您要继承,您需要了解副作用。
super
方法调用是否在内部调用任何其他方法调用?如果是,您需要采取适当的行动

继承(从底部开始)

构图

this.add() // this is the internal call to add() inside the Set implementation
s.addAll() // s is the Set<E> instance
super.addAll(...) // this calls the ForwardingSet implementation of addAll()
s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); // s is your InstrumentedSet instance
this.add()//这是在Set实现中对add()的内部调用
s、 addAll()//s是集合实例
super.addAll(…)//这将调用addAll()的ForwardingSet实现
s、 addAll(Arrays.asList(“Snap”、“Crackle”、“Pop”);//s是您的InstrumentedSet实例
InstrumentedSet#getAddCount()
返回6,因为数组(3)的大小添加了两次

//InstrumentedSet
public boolean addAll(Collection<? extends E> c) {
    addCount += c.size(); //here
    return super.addAll(c); //and here!
}
//InstrumentedSet

public boolean addAll(CollectionWhy you's be get six?您正在将三个元素添加到'InstrumentedSet',然后将其'addCount'相应地追加三次。在第一种情况下,返回的是6而不是3。@LuiggiMendoza Oh,因为
add()
请粘贴代码并运行它,然后查看。第一种情况下,您将得到6。Joshua Bloch用有效java解释了这一点。这是因为add和addAll方法中的addcount都是递增的,但addAll方法内部实现add方法。@user2708477是的,我错过了重写的
add()
。请参见我的编辑。@user2708477在
HashSet#addAll()
中,它调用
this.add()
,但事实证明
引用了
InstrumentedHashSet
的实例,因此
添加()
(使用count++)是执行的。InstrumentedSet返回3。但InstrumentedHashSet返回6。我知道为什么它是6。我想知道包装类(ForwardingSet)在这里实际上是如何帮助的“这里的帮助”是什么意思:您尝试运行此代码了吗?它为InstrumentSet返回3,但为InstrumentHashSet返回6。现在这很有意义,感谢您研究它。但是,您从
InstrumentedSet开始,getAddCount()返回6,因为数组(3)的大小添加了两次!
应该是
InstrumentedhasSet\getAddCount()返回6,因为数组(3)的大小添加了两次!
public class InstrumentedHashSet<E> extends HashSet<E> {
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
System.out.println(s.getAddCount());
@Override
public boolean add(E e) {
    addCount++;
    return super.add(e);
}
public class InstrumentedSet<E> extends ForwardingSet<E> {
private final Set<E> s;
public static void main(String[] args) {
    InstrumentedSet<String> s = new InstrumentedSet<String>(
                new HashSet<String>());
    s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
    System.out.println(s.getAddCount());
}
s.add() // s is your InstrumentedHashSet instance, because of polymorphism (inheritance), this adds to the count
this.add() // this is the internal call inside the HashSet#addAll()
super.addAll(...) // this calls the HashSet implementation of addAll which calls add() internally
s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); // s is your InstrumentedHashSet instance
this.add() // this is the internal call to add() inside the Set implementation
s.addAll() // s is the Set<E> instance
super.addAll(...) // this calls the ForwardingSet implementation of addAll()
s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); // s is your InstrumentedSet instance
//InstrumentedSet
public boolean addAll(Collection<? extends E> c) {
    addCount += c.size(); //here
    return super.addAll(c); //and here!
}