第16条提醒我们,对于不是为了继承而设计,并且没有文档说明的“外来”类进行子类化是多么危险。那么对于专门为了继承而设计并具有良好文档说明的类而言,这有意味着什么呢?

该类的文档必须精确的描述覆盖每个方法所带来的影响。(java.util.AbstractCollection)

 /*** 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: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 inerates 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 removed by this collection's iterator method does not implement the remove method.*/boolean remove(Object o);

该文档很明确的说明了,覆盖iterator 方法将会影响remove方法的行为。而且,它确切的描述了iterator方法返回的Iterator的行为将会影响remove方法的行为。

好的API应该描述一个给定的方法做了什么工作,而不是描述他是如何做到的。上面的API违反了这句话,这正式继承破坏了封装性所带来的不幸后果。

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

     /*** Removes from this list all of the elements whose index is between* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.* Shifts any succeeding elements to the left (reduces their index).* This call shortens the list by {@code (toIndex - fromIndex)} elements.* (If {@code toIndex==fromIndex}, this operation has no effect.)** <p>This method is called by the {@code clear} operation on this list* and its subLists.  Overriding this method to take advantage of* the internals of the list implementation can <i>substantially</i>* improve the performance of the {@code clear} operation on this list* and its subLists.** <p>This implementation gets a list iterator positioned before* {@code fromIndex}, and repeatedly calls {@code ListIterator.next}* followed by {@code ListIterator.remove} until the entire range has* been removed.  <b>Note: if {@code ListIterator.remove} requires linear* time, this implementation requires quadratic time.</b>** @param fromIndex index of first element to be removed* @param toIndex index after last element to be removed*/protected void removeRange(int fromIndex, int toIndex) ;
参数:
fromIndex 要移除的第一个元素的索引。
toIndex 要移除的最后一个元素的索引。

这个方法对于List实现的最终用户没有意义。提供该方法的唯一目的在于,使子类更容易提供针对子列表的快速clear方法。如果没有removeRange方法,当在子列表上调用clear方法,子类将不得不用平方级的时间来完成他的工作。否则,就得重新编写真个subList机制,这可不是件容易的事情!

因此,当你为了继承而设计的类的时候,如何决定应该暴露那些受保护的方法或者域呢?遗憾的是,并没有神奇的法则可供你使用。唯一的方法就是测试。

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

为了允许继承,类还必须遵守其他的一些约束。构造器绝不能调用可被覆盖的方法,无论是直接调用还是间接调用。
例如:

    public class Super{//Broken - constructor invokes an overridable methodpublic Super{overrideMe();}public void overrideMe(){}}

下面的子类覆盖了方法overrideMe,Super唯一的构造器就错误的调用了这个方法:

public final class Sub extends Super{private final Date date;//Blank final,set by constructorSub(){date=new Date();}//Overriding method invoked by superclass constructor@Overridepublic void overrideMe(){Systen.out.println(date);}public static void main(String[] args){Sub sub=new Sub();sub.overrideMe();}}

你可能会期待这个程序会打印出日期俩次,但是它第一次打印出的是null,因为overrideMe方法被Super构造器调用的时候,构造器Sub还没有机会初始化Date域。

在为了继承而设计的类的时候,Cloneable和Serializable接口出现了特殊的困难。如果类是为了继承而被设计的,无论实现这其中的那个接口通常都不是一个好主意,因为他们它一下实质性的负担转嫁到扩展这个类的程序员的身上。

如果你决定在一个为了继承而设计的类中实现Cloneable或者Serializable接口,就应该意识到,因为clone和readObject方法在行为上非常类似于构造器,所以类似的限制规则也是使用的:无论是clone还是readObject,都不可以调用可覆盖的方法,不管是以直接还是间接的方式。

如果你决定在一个为了继承而设计的类中实现Serializable,并且该类有一个readResolve或者writeReplace方法,就必须使readResolve或者writeReplace成为受保护的方法,而不是私有的方法。

Effective Java 类和接口 第17条:要么为继承而设计,并提供文档说明,要么就禁止继承相关推荐

  1. 【04】Effective Java - 类和接口

    为什么80%的码农都做不了架构师?>>>    1.使类和成员的可访问性最小化 封装是软件设计的基本原则之一,它的好处就是解除组成系统的各个模块之间的耦合关系,使得这些模块可以独立地 ...

  2. 读完 Effective Java,我整理了 59 条技巧!(含pdf)

    点击⬆️方"逆锋起笔",公众号回复 编程资源领取大佬们推荐的学习资料 上一篇:CTO 写低级 Bug,致公司 70 GB 数据泄露! 作者:Dong GuoChao 链接:http ...

  3. java类与接口练习

    java类与接口练习--coursera java 课程作业 1.注意代码应该使用题目中所要求的语法要素: 2.注意良好的代码风格: 3.注意提交整个project,上传压缩后的附件,互评时可被成功执 ...

  4. 初识java类的接口实现

    初识java类的接口实现 如果两个类之间不存在继承关系,且两个类都想实现同一个接口,两个类都必须实现接口中全部方法,否则报语法错误 如果两个类之间存在继承关系也想实现同一个接口,父类如果实现了某个接口 ...

  5. java计算机毕业设计即时高校信息发布系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计即时高校信息发布系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计即时高校信息发布系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构 ...

  6. 计算机毕业设计Java诚越园区垃圾分类信息科普系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java诚越园区垃圾分类信息科普系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java诚越园区垃圾分类信息科普系统(源码+系统+mysql数据库+lw文档) 本源码技术栈 ...

  7. 基于JAVA竞赛信息发布及组队系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署

    基于JAVA竞赛信息发布及组队系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署 基于JAVA竞赛信息发布及组队系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署 本源码技术栈 ...

  8. 基于JAVA三坑购物平台演示录像2020计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA三坑购物平台演示录像2020计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA三坑购物平台演示录像2020计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目 ...

  9. 基于JAVA面相高校学生的图书共享平台计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA面相高校学生的图书共享平台计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA面相高校学生的图书共享平台计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构 ...

最新文章

  1. Mars说光场(4)— 光场显示
  2. 良田高拍仪集成vue项目
  3. PHP获取MySQL执行sql语句的查询时间
  4. MFS分布式存储三:备份与恢复
  5. find 和 xargs 和 locate
  6. jenkins 手动执行_想知道如何用Jenkins自动执行Python脚本输出测试报告?
  7. vector 注意事项
  8. POJ NOI MATH-7826 分苹果
  9. Linux学习笔记之(2)~linux目录树概览和说明
  10. java各个版本下载地址
  11. 用计算机术语写诗,网上盛行写诗软件 电脑作诗毫无逻辑令人喷饭
  12. 谷歌浏览器安装JSON格式化插件
  13. 如何在matlab中设置colorbar
  14. larval 进程管理
  15. 安卓和苹果上线流程:
  16. KNN算法和Kernel KNN算法的区别
  17. 计算机教室怎么样布置,如何布置计算机教室
  18. centos 系统软件包管理 yum 本地yum配置 扩展源epel rpm 清除yum缓存 yum provides */vim 第十节课...
  19. 笔记整理,欢迎参观指导 ****补完****
  20. Vue使用ECharts完成2020年全国各地区GDP总量大数据可视化面板(附源码)

热门文章

  1. cad怎么将图层后置_CAD中如何将某一个图层置于其他图层之上???
  2. 沐阳JP1081B USB转网口 内核选项
  3. 网上咋打印?网上打印资料文件的平台有哪些
  4. C语言学生成绩信息管理系统课程设计报告
  5. 计算机网络几种常见协议
  6. Leetcode 1628. Design an Expression Tree With Evaluate Function [Python]
  7. tensorboard画图
  8. 小型电话薄管理系统(Mysql数据库)
  9. 【python基础】递归函数
  10. 高中数学基础-对数2.2.2对数函数图象及其性质(上)