【Effective Java】条17:为继承类专门设计并提供文档说明,否则不使用

【Effective Java】条16:复合优于继承中我们已经提到过使用继承的缺点。但如果是专为继承设计的,并提供文档说明,那是排除在外的情形。下面看看怎么专为继承设计类,并怎么提供文档说明。

  1. 该类的文档需明确说明重写任何方法的影响
    对于每个public或者protected的方法或者构造器,都需要指明该方法或者构造器调用了哪些可覆盖的方法,以什么顺序,每个调用结果是如何影响后续的处理。最好还需要说明在哪种情形下类会调用可重写的方法。

    JDK中,针对调用了可重写方法的方法,注释中在描述方法是做什么的文档后面,通常都添加了调用的说明,且通常都以This implementation开头。如java.util.AbstractCollectionremove方法,说明remove是依赖于iteratorremove方法的:

    public boolean remove(Object o)
    
    Removes a single instance of the specified element from this collection, if it is present (optional operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this collection contains one or more such elements. Returns true if this collection contained the specified element (or equivalently, if this collection changed as a result of the call).
    
    This implementation iterates over the collection looking for the specified element. If it finds the element, it removes the element from the collection using the iterator's remove method.
    
    Note that this implementation throws an UnsupportedOperationException if the iterator returned by this collection's iterator method does not implement the remove method and this collection contains the specified object.
  2. 类可以通过protected方法或者protected域来提供钩子,关联到内部工作流程中。如java.util.AbstractList中的removeRange方法:

    protected void removeRange(int fromIndex, int toIndex)
    
    Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive. Shifts any succeeding elements to the left (reduces their index). This call shortens the list by (toIndex - fromIndex) elements. (If toIndex==fromIndex, this operation has no effect.)
    This method is called by the clear operation on this list and its subLists. Overriding this method to take advantage of the internals of the list implementation can substantially improve the performance of the clear operation on this list and its subLists.
    
    This implementation gets a list iterator positioned before fromIndex, and repeatedly calls ListIterator.next followed by ListIterator.remove until the entire range has been removed. Note: if ListIterator.remove requires linear time, this implementation requires quadratic time.
    
    Parameters:
    fromIndex - index of first element to be removed
    toIndex - index after last element to be removed

    removeRange方法对于List实现的最终用户并无多大意义。提供该方法的唯一目的在于使子类更易于提供对字列表的快速clear方法。若没有removeRange方法,当在字列表上调用clear方法时,子类将不得不用平方级的时间来完成工作。==不是特别明白==

  3. 如果类是为继承设计,那么最好的方法就是自己写子类来测试是否暴露了不该暴露的接口

当然,在设计类继承时,也需要注意以下几点:
1. 构造器不应该调用(直接或间接)可重写的方法。举个反例:
“`
public class Super {
// Broken - constructor invokes an overridable method
public Super() {
overrideMe();
}

    public void overrideMe() {
    }
}

public final class Sub extends Super {
    private final Date date; // Blank final, set by constructor

    Sub() {
        date = new Date();
    }

    // Overriding method invoked by superclass constructor
    @Override public void overrideMe() {
        System.out.println(date);
    }

    //输出null和当前时间。因为先调用父类构造器。
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.overrideMe();
    }
}
```

2. 实现clone或者Serializable接口的类,clonereadObject方法都不能调用可重写的方法(类似于构造器)
3. 如果为继承设计的类实现Serializable接口,则readResolvewriteReplace方法需要用protected修饰,而不是private,否则会被子类忽略

猜你喜欢

转载自blog.csdn.net/xl890727/article/details/80319328