在改写equals的时候请遵守通用约定
不改写equals方法时,每个实例只与自身相等,如果满足一下任意一个条件,则不需要改写equals方法:
- 一个类的实例本质上都是唯一的
- 不关心类是否支持“逻辑相等”功能
- 超类已经改写了equals方法
- 类是私有的,并且可以确定它的equals方法永远不会被调用
改写equals方法时,需要遵守的约定:
- 自反性(自己和自己相等)
- 对称性(x和y相等,反过来y也和x相等)
- 传递性(x与y相等,y与z相等,则x与z相等)
- 一致性(x与y相等,则不论进行多少次比较,结果都不会变)
- 非空性(o.equals(null)一定返回false)
改写equals时总是要改写hashCode
改写一个类的equals方法后,两个不同的对象可能在逻辑上是相等的,但是根据Object的hashCode方法来看,它们仅仅是两个对象,没有其他共同的地方,因此hashCode方法返回的不会是两个相等的整数,这可能会导致一些问题。
如果你把一个对象放入Map中当作Key,此后你创建一个与原对象逻辑相等的新对象用作Key去取值,你会发现结果返回的是null
因此你应该针对对象间用来进行逻辑比较的值来确定hashCode,该值应该是获取hashCode表达式中的唯一变量。
总是要改写toString
这个不用多说了,对象如果不改写toString方法,会直接输出“类名@:hashCode”,为了方便调试,总是要改写对象的toString方法,eclipse/Myeclipse都提供这个方法。
一个改写toString方法的例子
public class Person {
public String name;
public boolean sex;
public int age;
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
谨慎地改写clone
按照书中的话来讲,能不重写clone就不要去重写,因为它带来的问题太多了。关于“深拷贝”和“浅拷贝”,可以转战这篇博客:【Java深入】深拷贝与浅拷贝详解,但这篇只提到了反序列化方法,其实还可以用反射和表达树来实现深拷贝。
书中是不建议自定义重写clone方法的,如果非要重写书中总结为一句话:clone方法就是一个构造器,你必须确保它不会伤害到原始的对象,并确保正确地创建被克隆对象中的约束条件。
还有一点是在别人博客上看到的,出处https://blog.csdn.net/wusd1256/article/details/80282015:
查看Cloneable接口实际上可以发现里面什么方法都没有,clone方法却来自Object类,继承了Cloneable接口为什么就能重写clone方法了呢?原因在于clone方法在Object类中的修饰符是protected,而Cloneable接口和Object处于同一个包下,熟悉修饰符的都知道protected的权限限定在同一个包下或者其子类。Cloneable和Object同属于一个包,Cloneable自然能继承clone方法,继承了Cloneable接口的成为了它的子类同样也就继承了clone方法。
考虑实现Comparable接口
其实我感觉这点没什么可说的,就是实现Comparable接口中的compareTo方法,自己编写比较规则。
此外Arrays和Collections都已经提供了sort方法,而且如果需要在数组/集合内部定义排序规则,还可以新建一个Comparator实例,自己实现compare方法,再为数组或集合调用就好了。