你会遇到这种情况么:
A'类继承A类
A‘重写 父类A的a1,a2方法 a1’,a2‘
但是 A类中的a1是基于a2方法去实现的。
如果a1’调用父类A类的a1方法,那么就会继续调用到a2方法, 用于A‘继承A重写了a2方法,间接的调用了a2’ 方法。
a1‘与a2’间的业务关联,导致 A‘类属性值重复变更。
测试码:
InstrumentedHashSet.java
// Broken - Inappropriate use of inheritance!
import java.util.*;
public class InstrumentedHashSet<E> extends HashSet<E> {
// The number of attempted element insertions
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("Snap", "Crackle", "Pop"));
System.out.println(s.getAddCount());
}
}
InstrumentedHashSet类中main方法s.addAll(Arrays.asList("Snap", "Crackle", "Pop")); ---->调用@Override public boolean addAll(Collection<? extends E> c)
return super.addAll(c);------>调用HashSet的addAll实现,AbstractCollection.java中
public boolean addAll(Collection<? extends E> c)
/**
* {@inheritDoc}
*
* <p>This implementation iterates over the specified collection, and adds
* each object returned by the iterator to this collection, in turn.
*
* <p>Note that this implementation will throw an
* <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is
* overridden (assuming the specified collection is non-empty).
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*
* @see #add(Object)
*/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
---->最终又调用了InstrumentedHashSet覆盖了的add方法,元素每调用一次,addCount自增一次。
InstrumentedHashSet.java
@Override public boolean add(E e) {
addCount++;
return super.add(e);
}
console控制台打印结果如下:
Connected to the target VM, address: '127.0.0.1:50009', transport: 'socket'
6
Disconnected from the target VM, address: '127.0.0.1:50009', transport: 'socket'
Process finished with exit code 0
结果为6,实际上 我们想要的结果是3
===============复合优先于继承================
避免前面提到的问题,不扩展现有的类,
而是在新的类中添加一个私有域,它引用现有的一个实例,这种设计被称作”复合(composition)” 。
因为现有的类变成了新类的一个组件。
新类中的每个实例方法都可以调用被包含的现有类实例中对应的方法,
并返回他的结果,这被称为转发(forwarding),
新类中的方法被称为 转发方法(forwarding method)
好处是什么:这得到的类稳固,它不依赖于现有类的实现细节。即使现有的类添加了新的方法,不影响新的类。
InstrumentedSet.java
import java.util.*;
public class InstrumentedSet<E> extends ForwardingSet<E> {
private int addCount = 0;
public InstrumentedSet(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) {
InstrumentedSet<String> s =
new InstrumentedSet<String>(new HashSet<String>());
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
System.out.println(s.getAddCount());
}
}
ForwardingSet.java
import java.util.*;
public class ForwardingSet<E> implements Set<E> {
private final Set<E> s;
public ForwardingSet(Set<E> s) { this.s = s; }
public void clear() { s.clear(); }
public boolean contains(Object o) { return s.contains(o); }
public boolean isEmpty() { return s.isEmpty(); }
public int size() { return s.size(); }
public Iterator<E> iterator() { return s.iterator(); }
public boolean add(E e) { return s.add(e); }
public boolean remove(Object o) { return s.remove(o); }
public boolean containsAll(Collection<?> c)
{ return s.containsAll(c); }
public boolean addAll(Collection<? extends E> c)
{ return s.addAll(c); }
public boolean removeAll(Collection<?> c)
{ return s.removeAll(c); }
public boolean retainAll(Collection<?> c)
{ return s.retainAll(c); }
public Object[] toArray() { return s.toArray(); }
public <T> T[] toArray(T[] a) { return s.toArray(a); }
@Override public boolean equals(Object o)
{ return s.equals(o); }
@Override public int hashCode() { return s.hashCode(); }
@Override public String toString() { return s.toString(); }
}
console控制台:
InstrumentedSet
Connected to the target VM, address: '127.0.0.1:50634', transport: 'socket'
3
Disconnected from the target VM, address: '127.0.0.1:50634', transport: 'socket'
Process finished with exit code 0