effective java(17) 之要么为继承而设计,并提供文档说明,要么就禁止继承

来源:互联网 发布:好用的洗面奶知乎 编辑:程序博客网 时间:2024/06/06 02:14
effective java 之要么为继承而设计,并提供文档说明,要么就禁止继承


1、 对于专门为了继承而设计并且具有良好文档说明的类而言,该类的文档必须精确地描述覆盖每个方法所带来的影响。
该类必须有文档说明它可覆盖的方法的自用性。
对于每个公有的或受保护的方法或者构造器,它的文档必须指明该方法或者构造器调用了哪些可覆盖的方法,是以什么顺序调用的,每个调用的结果又是如何影响后续的处理过程的。
更一般的,类必须在文档中说明,在哪些情况下它会调用可覆盖的方法。


2、按惯例,如果方法调用到了可覆盖的方法,在它的文档注释的末尾应该包含关于这些调用的描述信息。
这段描述信息要以这样的句子开头:“This implementation...”。这样的句子不应该被认为是在表明该行为可能会随着版本的变迁而改变。它意味着这段描述关注该方法的内部工作情况。


3、在第16条的情形中,程序员在子类化HashSet的时候,并无法说明覆盖add方法是否会影响addAll方法的行为。
关于程序文档的格言:好的API文档应该打桩一个给定的方法做了什么工作,而不是描述它是如何做到的。
所以,为了设计一个类的文档,以便它能够被安全的子类化,必须描述清楚那些有可能未定义的实现细节。


4、为了继承而进行设计不仅仅涉及自用模式的文档设计。为了使程序员能够编写出更加有效的子类,而无需随不必要的痛苦,类必须通过某种形式提供适当的钩子,以便能够进入到它的内部工作流程中,这种形式可以是精心选择的受保护的方法,也可以是受保护的域,后者比较少见。


5、一个为了继承而设计的类(超类)应该是:
a.为了允许被继承,无论是直接还是间接,构造方法都不能够调用非final方法。否则程序有可能失败。
由于超类的构造方法比子类的构造方法先执行,所以子类中改写版本的方法将会在子类的构造方法运行之前先被调用。如果该改写版本的方法依赖于子类构造方法所执行的初始化工作,那么该方法将不会如预期执行。
构造器决不能调用可被覆盖的方法。
public class Sub extends Super {private final Date date;public Sub() {date = new Date();}public void method() {System.out.println(date);}public static void main(String[] args) {Sub s = new Sub();s.method();}}class Super {public Super() {method();}public void method() {System.out.println("Super method");}}

构造器中调用了可覆盖方法,而导致NullPointerException。


b.设计的超类实现Serializable或者Cloneable接口都是很麻烦的事情。因为clone和readObject都类似一个构造方法。
所以超类要实现这两个接口就必须遵循这个规则:clone和readObject都不能够调用可改写的方法,无论是直接还是间接方式。对于readObject方法,子类改写版本的方法将在子类的状态被反序列化之前先执行;

对于clone方法,改变版本的方法将在子类的clone方法有机会修正被克隆对象的状态之前先被执行。无论哪种情况,都可能导致程序失败,在clone方法中,这种失败会导致损害原始对象以及克隆的对象本身。


c.如果超类实现了Serializable接口,并且该类有一个readResolve或者writeReplace方法,那么就必须是readResolve或者writeReplace方法成为protectd,而不是private。如果是私有的话,那么子类会忽略掉这两个方法。

d.对于一些不需要被继承的类,最好是把它定义为不能够被继承的类。可以使用final或者提供静态工厂方式来提供对象。



每天努力一点,每天都在进步。
阅读全文
0 0
原创粉丝点击