类和接口

第 15 条:使类和成员的可访问性最小化

公有静态 final 域暴露常量,要么包含基本类型值,要么包含指向不可变对象的引用

第 16 条:在公有类中使用访问方法而非公有域

  • 公有类不应该暴露可变域,因为其客户端代码遍布各处,将来极难改变内部表示法
  • 公有类暴露不可变域危害较小,事实上也不应该
  • 包级私有或私有嵌套类,直接暴露数据域并没有本质错误

第 17 条:使可变性最小化

如果类不能被做成不可变,仍然应该尽可能限制它的可变性,降低对象可以存在的状态数!构造器应该创建完全初始化的对象,并建立所有的约束关系,不要在构造器或静态工厂之外再提供公有的初始化方法,除非有足够的理由!

第 18 条:复合优先于继承

在包内部使用继承是安全的,跨越包边界的继承是危险的

第 19 条:要么为继承而设计,并提供文档说明,要么就禁止继承

对于专门为继承而设计且有良好文档说明的类

  • 该类文档必须有文档说明它可覆盖方法的自用性
  • 该类必须通过某种形式提供适当的钩子,以便能进入它的内部工作流程中
  • 构造器,clone 或者 readObject 绝不能调用可被覆盖的方法,不管是直接还是间接

并非为了安全进行子类化而设计和编写文档的类,要禁止子类化

  • 将类声明为 final
  • 将构造器变成 private 或 package-private,并增加一些公有的静态工厂来替代构造器

第 20 条:接口优于抽象类

接口与抽象类的区别

  • 抽象类允许包含某些方法的实现,接口不允许
  • 为实现抽象类定义类型,类必须成为抽象类的子类,而接口则不用关心类层次
  • 现有类容易被更新以实现新接口,一般无法更新现有类来扩展新抽象类
  • 接口是定义 mixin 的理想选择,mixin 用来表明类提供了某些可供选择的行为,允许任选功能混合到类型主要功能中
  • 接口允许构造非层次结构的类型框架

第 21 条: 为子类设计接口

编写一个默认方法并不总是可能的,它保留了每个可能的实现的所有不变量。

在默认方法的情况下,接口的现有实现类可以在没有错误或警告的情况下编译,但在运行时会失败。

第 22 条:接口只用于定义类型

常量接口模式是对接口的不良使用,是反面典型,不值得效仿!

关键原因:如果类实现常量接口,将来版本中类修改了,不需要这些常量了,它还依然必须实现这个接口,以确保二进制兼容性!

第 23 条:类层次优于标签类

类层次!首先,定义一个抽象类作为根类,提取公用方法到抽象类中!然后,为每种原始标签类定义根类的具体子类,子类包含特定域和方法!

第 24 条:优先考虑静态成员类,而不是非静态类

第 25 条: 将源文件限制为单个顶级类

虽然 Java 编译器允许在单个源文件中定义多个顶级类,但这样做没有任何好处,并且存在重大风险。 风险源于在源文件中定义多个顶级类使得为类提供多个定义成为可能。 使用哪个定义会受到源文件传递给编译器的顺序的影响。

Author: iMine
Link: https://imine141.github.io/2020/07/26/Effective%20java/%E7%B1%BB%E5%92%8C%E6%8E%A5%E5%8F%A3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.