Effective Java读书笔记(2)

Posted by alonealice on 2016-11-07

覆盖equals方法时的通用约定

1.自反性:对于任何非null的对象x,x.equals(x)一定是true
2.对称性:对于任何非null对象x,y,x.equals(y)为true时,y.equals(x)也一定为true
3.传递性:x.equals(y)等于true,y.equals(z)也为true,那么x.equals(z)也一定为true
4.一致性:在没有修改两个对象信息的情况下,多次调用equals方法会一致的返回true或false
5.非空性:对于任何非空对象x,x.equals(null)一定是false
这些约定看似简单,在覆盖equals方法时一定要注意。

覆盖equals方法时要重写hashcode方法

hashcode通用约定:
1.程序执行期间,hashcode多次调用时返回的是同一个值,多次执行过程中可以不一样。
2.如果两个对象根据equals方法判断相等,那么它们的hashcode也应该相等。
3.两个对象不相等,hashcode可能不相等,也可能相等,但是不相等可以提高效率。

覆盖toString

自定义类时最好要重写toString方法。toString方法返回的值最好有固定的格式,并且有文档详细说明。即使没有固定的格式,也要有文档加以说明已增强可读性。

考虑实现Comparable接口

类可以实现Comparable接口来对对象进行排序。实现Comparable接口后会重写一个CompareTo方法,返回int值。返回0时说明两者顺序相等,返回1说明比较对象比本对象顺序靠前,返回-1说明靠后。

使类和成员的可访问性最小化

一个模块对于其他的外部模块而言,要尽可能的隐藏其内部的数据结构和实现细节,这个概念被称为封装。
好处:可以有效的接触各个模块之间的耦合关系,使这些模块能够独立的开发、测试、优化和修改。
规则:1.尽可能的使每个类或成员不被外界访问,就是说在不影响功能的情况下,能包私有就不公有,能私有就不包私有。
2.实例域决不能是公有的。
3.静态域也不能是公有的。

在公有类中使用访问方法代替公有域

将域的可访问性设置为private,使用相关的public set和get方法去访问类。

类可变性最小化

不可变类是指实例的所有信息在其创建时就提供,之后再也无法改变。这种类比普通的类更加容易设计、实现和使用,而且更加安全。
将类的可变性最小化规则:
1.不提供任何可以修改对象的状态的方法
2.使类不能被扩展(final修饰)
3.所有的域都是私有的
4.所有的域都是final的
5.确保对于任何可变组件的互斥访问

复合优先于继承

继承打破了程序的封装性。当超类中的实现随着版本的更新而变化时,子类可能会遭到破坏,所以子类也只能变化。所以继承只能在子类和超类确实存在子类型关系时使用才是合适的。而复用除了能获得更好的健壮性之外,还能带来更好的灵活性。

要么为继承而设计,并提供文档,要么就禁止继承

鉴于上面继承所可能带来的问题,类在使用继承的过程中,必须要有文档。那有怎样写文档呢?
一般情况下,api文档应该描述方法做了什么工作,但是在这里,你必须详细的描述方法是怎样工作的。这相当于将类内部的实现原理暴露出去。因此在设计类的时候,你就必须要考虑要暴露哪些方法或域。

接口优于抽象类

1.现有类容易实现新的接口 比如现在A类实现B接口,现在又需要A实现C接口的方法,只需要A再继承C接口即可。而如果A继承B,如果又要有C的方法,那就只能将B继承C,这样会使B也有C方法,会伤害类层次而且B也不需要C的方法。
2.接口可以继承多个接口从而实现非层次接口的类型框架

接口只用于定义类型

常量接口没有任何方法,只有静态final域,这种模式是对接口的不良使用,