EffectiveJava-2-对于所有对象都通用的方法

尽管Object是一个具体类,但是设计它主要是为了扩展, 它的所有非final方法都有明确的通用规定;

本节主要讲Object类的非final方法 & Comparable.compareTo()方法;

覆盖equals时请遵守通用约定:

1. equals通用约定:

- equals方法实现了等价关系

- 自反性:对于任何非null的引用值x,x.equals(x)必须返回true

- 对称性:对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true

- 传递性:对于任何非null的引用值x,y和z,如果x.equals(y)返回true,并且y.equals(z)返回true,则x.equals(z)也必须返回true

- 一致性:对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,则多次调用x.equals(y)的返回结果是一致的

2. 不需要覆盖equals对情况:

- 类对每个实例本质上都是唯一的,例如Thread,每个实例都对应一个线程;

- 不关心类是否提供了"逻辑相等"的测试功能:如Random可以覆盖equals检查两个实例是否产生相同的随机数序列,但设计者并不认为用户需要或期望这样的功能,所以并没有重写equals方法; 

- 超类已经覆盖类equals,且对于子类也适用时; 

- 类是私有的或是包级私有的,可以确定他的equals方法永远不会被调用,此时最好覆盖equals方法,防止被意外调用;

3. 需要覆盖equals的情况:

"值等"情形:类具有自己特有的"逻辑相等"概念,而且超类还没有覆盖equals以实现期望的行为;

4. 注意equals方法的写法:

不要将equals声明中的Object对象替换成其他的类型,这可能带来不可预知的麻烦;

覆盖equals时总要覆盖hashCode

1. hashCode通用约定:

- 在程序执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数,同一个应用程序的多次执行过程中,返回的整数可以不一致; 

- 如果两个对象使用equals比较是相等的,那么hashCode必须产生同样的整数结果; 

- 如果两个对象使用equals比较是不相等的,那么hashCode方法不一定要产生不同的整数结果,但是,程序员应该知道,给不想等的对象产生不同的hashCode可能提高散列表的性能;

2. 为不相等的对象产生不相等的散列码(hashCode方法的返回值):

- 将某个非零常数值赋值给result,如result=17

- 为每个关键域f(指equals涉及的域)计算散列码,并合并到result中

计算:

合并,公式:result=31*result+c;

- 返回result

可以把冗余域(可以根据其他关键域计算出来)排除;

必须把equals中没有用到的域排除;

始终覆盖toString

通用约定:

- 建议所有子类都覆盖这个方法, 返回对象中包含的所有值得关注的信息;

- 提供好的toString实现可以使类用起来更加舒适;

谨慎的覆盖clone

- implements Cloneable, 重写clone方法;

- 注意不能伤害到原始对象,并确保正确到创建被克隆对象中到约束条件;

- 可能有必要从某些域中去掉final修饰符;

- 一些专家级到程序员干脆从来不去覆盖clone方法,也从来不去调用它,除非拷贝数组;

- 对于一个为了继承而设计的类,如果你未能提供行为良好的受保护的clone方法,它的子类就不可能实现Cloneable接口;

考虑实现Comparable接口

遵守自反性,对称性,传递性

注意: 

如果想给一个实现了Comparable接口的类增加值组件,请不要扩展这个类,

要编写一个不相关的类,其中包含第一个类的一个实例,并提供一个视图(view)方法返回这个实例,这样既可以在第二个类上自由的实现compareTo方法,也允许客户端在必要的时候,将第二个类的实例视同第一个类的实例;

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章

猜你喜欢

转载自blog.csdn.net/o118abcdef/article/details/112259215