Effective Java 第三版——19. 如果使用继承则设计,并文档说明,否则不该使用
Tips
《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化。
在这里第一时间翻译成中文版。供大家学习分享之用。
19. 如果使用继承则设计,并文档说明,否则不该使用
条目 18中提醒你注意继承没有设计和文档说明的“外来”类的子类化的危险。 那么为了继承而设计和文档说明一个类是什么意思呢?
首先,这个类必须准确地描述重写这个方法带来的影响。 换句话说,该类必须文档说明可重写方法的自用性(self-use)。 对于每个公共或受保护的方法,文档必须指明方法调用哪些重写方法,以何种顺序以及每次调用的结果如何影响后续处理。 (重写方法,这里是指非final修饰的方法,无论是公开还是保护的。)更一般地说,一个类必须文档说明任何可能调用可重写方法的情况。 例如,后台线程或者静态初始化代码块可能会调用这样的方法。
调用可重写方法的方法在文档注释结束时包含对这些调用的描述。 这些描述在规范中特定部分,标记为“Implementation Requirements,”,由Javadoc标签@implSpec
生成。 本节介绍该方法的内部工作原理。 下面是从java.util.AbstractCollection
类的规范中拷贝的例子:
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 Objects.equals(o, 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).
Implementation Requirements: 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.
从该集合中删除指定元素的单个实例(如果存在,optional
实例操作)。 更正式地说,如果这个集合包含一个或多个这样的元素,删除使得Objects.equals(o, e)
的一个元素e。 如果此集合包含指定的元素(或者等同于此集合因调用而发生了更改),则返回true。
实现要求:这个实现迭代遍历集合查找指定元素。 如果找到元素,则使用迭代器的remove
方法从集合中删除元素。 请注意,如果此集合的iterator
方法返回的迭代器未实现remove
方法,并且此集合包含指定的对象,则此实现将引发UnsupportedOperationException
异常。
这个文档毫无疑问地说明,重写iterator
方法会影响remove
方法的行为。 它还描述了iterator
方法返回的Iterator行为将如何影响remove
方法的行为。 与条目 18中的情况相反,在这种情况下,程序员继承HashSe
t并不能说明重写add方法是否会影响addAll方法的行为。
但是,这是否违背了一个良好的API文档应该描述给定的方法是什么,而不是它是如何做的呢? 是的,它确实!这是继承违反封装这一事实的不幸后果。要文档说明一个类以便可以安全地进行子类化,必须描述清楚那些没有详细说明的实现细节。
@implSpec
标签是在Java 8中添加的,并且在Java 9中被大量使用。这个标签应该默认启用,但是从Java 9开始,除非通过命令行开关-tag “apiNote