《Effective java》读书记录-第17条-要么为继承而设计,并提供文档说明,要么就禁止继承

时间:2022-04-04 17:50:40

可继承类必须有文档说明它可覆盖(overridable)的方法的自用性(self-use)。

好的API文档应该描述一个给定的方法做了什么工作,而不是描述它是如何做到的。

类必须通过某种形式提供适当的钩子(hook),以便能够进入到它的内部工作流程中,这种形式可以是精心选择的受保护(protected)方法,也可以受保护的域(比较少见)。

对于为了继承而设计的类,唯一的测试方法就是编写子类。经验表明,3个子类通常足以测试一个可扩展的类。

必须在发布类之前先编写子类进行测试。

为了允许继承,类还必须遵守一些规则。

1.构造器决不能调用可被覆盖的方法

public class Super {
    
    public Super () {
        overrideMe();
    }

    public void overrideMe(){

    }
}
public class Sub extends Super {
    private final Date date;

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

    @Override
    public void overrideMe() {
        System.out.println(date.toString());
    }

    public static void main(String[] args){
        Sub sub=new Sub();
        sub.overrideMe();
    }
}
上述代码就错误的在构造器中调用了可覆盖方法,而导致NullPointerException。

因为超类构造器会在子类构造器之前运行,所以子类的覆盖方法会在子类构造器之前被运行,这样就导致了上述代码的错误。

 为了继承而设计的类如果实现了Cloneable和 Serializable接口会出现特殊的困难

无论是clone还是readObject,都不可以调用可覆盖的方法,不管是以直接还是间接的方式。

为了继承而设计的类,对这个类会有一些实质性的限制

但是,对于普通的具体类应该怎么办呢?它们既不是final的,也不是为了子类化设计和编写文档的。

这个问题的最佳解决方案是,对于那些并非为了安全地进行子类化而设计和编写文档的类,要禁止子类化。禁止子类化的方法由两种,类声明为final、所有的构造器私有化或包级私有化,并提供公有的静态工厂方法。

这条建议可能会引来争议,因为很多程序员已经习惯对普通的具体类进行子类化,以便增加新的功能。

如果类是实现了某个接口,那么可以通过包装类的方式来处理。

如果类没有实现具体的接口,禁止继承可能会带来不便。那么需要确保这个类永远不会自己调用自己的任何可覆盖的方法(可覆盖方法永远不会被自用),这样覆盖方法将永远不会影响其他任何方法的行为。