第4章 类和接口
类和接口是Java程序设计语言的核心,它们也是Java语言的基本抽象单元。Java语言提供了许多强大的基本元素,供程序员用来设计类和接口。
13. 使类和成员的可访问性最小化
要区别设计良好的模块与设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节。设计良好的模块会隐藏所有的实现细节,把它的API与它的实现清晰隔离开来。然后,模块直接只通过他们的API进行通信。一个模块不需要知道其他模块的内部工作情况。这个概念被称为信息隐藏或封装,是软件设计的基本原则之一。
Java程序语言提供了许多机制来协助信息隐藏。访问控制机制决定了类,接口和成员的可访问性。
实体的可访问性是由该实体声明所在的位置,以及该实体声明中所出现的访问修饰符(private,protected和public)共同决定的。
对于顶层的类和接口,只有两种可能的访问级别:包级私有和公有。
如果一个包级私有的顶层类或接口,只是在某一个类的内部被用到,就应该考虑使它成为唯一使用它的那个类的私有嵌套类。这样可以将它的可访问访问从包中的所有类缩小到了使用它的那个类。
对于成员(域,方法,嵌套类或嵌套接口)有4种访问级别:
- 私有的--只有在声明该成员的顶层类内部才可以访问这个成员;
- 包级私有的--缺省访问级别,没有为成员指定访问修饰符;
- 受保护的--声明该成员的类的子类可以访问这个成员,并且声明该成员的包内部的任何类也可以访问这个成员;
- 公有的--在任何地方都可以访问该成员;
实例域决不能是公有的,如果域是非final的,或者是一个指向可变对象的final引用,那个一旦使这个域成为公有的,就放弃了堆存储在这个域中的值进行限制的能力,这意味着,你也放弃了强制这个域不可变的能力。
长度非零的数组总是可变的,所以类具有公有的静态final数组域,或者返回这种域的访问方法,这几乎总是错误的。
private static final Thing[] VLAUES = {...}
public static fianl List<Thing> VALUES_LIST = Collections.unmodifiableList(Arrays.asList(VALUES)) 或 public static final Thing[] values() {
return VALUES.clone();
}
总结:尽可能降低可访问性,除了公有静态final域的特殊情形之外,公有类都不应该包含公有域。并且要确保公有静态final域所引用的对象都是不可变的。
14. 在公有类中使用访问方法而非公有域
公有类永远都不应该暴露可变的域。
15. 使可变性最小化
不可变类只是其实例不能被修改的类,每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期内固定不变。
存在不可变类有许多理由:不可变的类比可变类更加易于设计、实现和使用,不容易出错,且更加安全。
为了使类称为不可变,要遵循下面5条规则:
- 不要提供任何会修改对象状态的方法;
- 保证类不会被扩展;
- 使所有的域都是final的;
- 使所有的域都成为私有的;
- 确保对于任何可变组件的互斥访问
除非有令人信服的理由要使域变成是非final的,否则要使每个域都是final的。
16. 复合优先于继承
与方法调用不同的是,继承打破了封装性。换句话说,子类依赖于其超类中特定功能的实现细节。超类的实现有可能会随着发行版的不同而有所变化,如果真的发生了变化,子类可能会遭到破坏,即使它的代码完全没有改变。因此,子类必须要跟着其超类的更新而演变。
17. 要么为继承而设计,并提供文档说明,要么就禁止继承
18. 接口优于抽象类
接口和抽象类明显的区别在于,抽象类允许包含某些方法的实现,但是接口则不允许。
(1)现有的类可以很容易被更新,以实现新的接口。当Comparable接口被引入到Java平台中时,会更新虚度现有的类,以实现Comparable接口。因为Java支持单继承多多实现。
(2)接口是定义mixin(混合类型)的理想选择。
(3)接口允许我们构造非层次结构的类型框架。
x.参考文档
《Effective Java中文版 第2版》