第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. MySQL WHERE语句筛选操作符
  2. Machine Learning:如何选择机器学习算法?
  3. 不得不看的17 个linux实用技巧
  4. vb.net2019- 对象 (Visual Basic)
  5. html 鼠标图标做成动画效果,怎么实现鼠标经过图标动画效果
  6. java多张图片合成一张_1分钟学会“全景照片”拍摄技巧,从单反拍摄到PS合成,收藏备用...
  7. 信息奥赛一本通(1112:最大值和最小值的差)
  8. 虚拟机网络连接模式中桥接模式和NAT模式的区别
  9. 求区间不同数的个数 树状数组||莫队算法
  10. php resultful接口,来自REST ful PHP服务器的完整日历事件
  11. 一个Android项目被360报毒的解决方案
  12. postman 配置参数自动签名
  13. ”latest”(已经确认了的), “earliest”(创世区块的) , “pending”(包含未确认的交易的余额)
  14. win+linux双系统实现efi共存(即通过linux启动界面切换系统)
  15. Joel Spolsky对计算机学生的建议
  16. 60个实用Android框架排行榜
  17. project子项目之间任务关联_project项目任务类型,就这么简单
  18. 互联网软件开发和企业软件开发
  19. 有点激动,Python实现视频号自动赚钱!
  20. 【李宏毅机器学习CP21】(task6)卷积神经网络

热门文章

  1. 微信小程序base64图片转换临时链接
  2. Ruoyi框架学习总结--总览篇
  3. 基于ssm小学芙童币和芙童印章管理系统-计算机毕业设计源码文档
  4. python 生成pdf 文字和图片_Python系列—PDF文本与图片抽取
  5. [DEV] 陷阱技术探秘 ──动态汉化Windows技术的分析
  6. 恩兔NS-1刷ARMBIAN教程
  7. matplotlib 点线动画
  8. 如何取汉字的第一个拼音字母(一)
  9. VS Code快速实现Git PR操作
  10. 名帖77 刘弘珪 楷书《金刚般若波罗蜜经》