日期:2014-05-20  浏览次数:20985 次

继承问题(复合优于继承)
最近在读Effective Java这本书,讲到了item 16:复合优先于继承
1.说是一个类,如果继承了另一个类。有可能,父类在后期版本中加了一个新的方法,但是这个方法名在子类中已经存在。这就会出现,编译错误,或者父类的新方法被子类覆盖的问题。
2.然后提出了用复合取代继承。即把原来的“子类”增加一个私有的成员变量,指向“父类”的一个实例。可以解决上面提出的问题。(注,这里的“子类”,“父类”只是为了好描述问题,没改变之前,他们是有继承关系的)
3.他们给出了两个例子来说明问题。
4.我把他们的例子拿来跑了一下,好像问题没解决。还是我哪里理解错了?望大神们解答一下
5.我的问题主要在代码的注释里,麻烦大家看一下。有没看清楚问题的可以提问
6.先说 一以下代码要实现的功能,就是为set这个接口扩展一个计数器。

代码一:继承的(也即是书中提到的有问题的代码)

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

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);
}
@Override 
public boolean addAll(Collection<? extends E> c){
addCount += c.size();
return super.addAll(c);
}
public int getAddCount(){
return addCount;
}
public static void main(String[] args) {
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("","",""));
System.out.println(s.getAddCount());//这里如果正确的话,应该输出3,但是这里输出6。他们的解释是因为addAll方法调用的是add方法。即新类受到了父类的影响,所以提出了下面的解决方法
}
}


代码二:把继承改为复合的(也即是书中提到的修复问题的代码)

//Wrapper class - use composition in place of inheritance
public class InstrumentedHashSet2<E> extends ForwardingSet<E>{

private int addCount = 0;
public InstrumentedHashSet2(Set<E> s) {
super(s);
}

@Override
public boolean add(E e){
addCount++;
return super.add(e);
}
@Override 
public boolean addAll(Collection<? extends E> c){
addCount += c.size();
return super.addAll(c);
}

public int getAddCount(){
return addCount;
}

public static void main(String[] args) {
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("","",""));
System.out.println(s.getAddCount());//我觉得既然是改进的代码,这里就应该输出3了,但是怎么还是输出6.
}
}
/*
 * 
**/
class ForwardingSet<E> implements Set<E>{
//改进的地方:没有继承HashSet或者TreeSet,而是在这里加了一个私有成员变量。
         //文中提到,这样写,不依赖于现有的类(Set)的实现,不会受到现有类(Set)的影响
         //我怎么觉得还是会受到影响呢?比如Set添加了一个新方法A(),还是会影响到上面那个类的(如果上面那个类已经存在A(),上面那个类也会覆盖Set中的A()方法)
private final Set<E> s;//增加一个私有的成员变量
public ForwardingSet(Set<E> s){this.s = s;}

@Override
public boolean add(E e) {return s.add(e);}
@Override
public boolean addAll(Collection<? extends E> c) {return s.addAll(c);}
        //省略剩下方法的复写,但是和上面两个方法类似,由于没用到,我也就不拿出来了,有点长

}

------解决方案--------------------