与本章(前面3条)所讨论的方法不同,compareTo方法在Object中并没有被声明,它是java.lang.Comparable接口中唯一的方法。实现这一接口,也可以说类具有了“内在排序能力”。
compareTo方法除了允许比较相等外,还可以比较大小。通常如果 x < y ,则 x.compareTo(y) 返回一个负整数(通常是 -1);如果 x.equals(y) == true ,则 x.compareTo(y) 返回 0;如果 x > y ,则 x.compareTo(y) 返回一个正整数(通常是 1)
compareTo具有和equals相似的约定:
1)自反性:x.compareTo(x)一定为true
2)对称性:当且仅当x.compareTo(y) 为 0;那么y.compareTo(x)也必须为 0
3)传递性:如果x.compareTo(y) == 0,sgn(x.compareTo(z)) == sgn(y.compareTo(z)) 必须成立 (sgn为取正负返回 -1; 0; 1)
如果x.compareTo(y) < 0,y.compareTo(z) < 0;那么x.compareTo(x) 也必须 < 0
4)一致性:对于任意引用值x和y,如果用于compareTo比较的对象信息没有被修改的话,那么多次调用x.compareTo(y)返回的值是一致的
5)强力建议:(x.compareTo(y) == 0) == (x.equals(y)),但这并不是严格要求。一般而言,任何实现了Comarable接口的类,若违反了这个条件,应该明确予以说明。推荐这样的说法:“注意:该类具有内在的排序能力,但是与equals不一致。”
一个例子是 BigDecimal ,这是一个没有满足这一条件的类(其实这一条并非真正的规则,仅仅是个建议而已)。我们实例化2个对象:new BigDecimal("1.0") 和 new BigDecimal("1.00"),若把这2个对象放入HashSet中,HashSet将有2个元素,而放入TreeSet,则这个TreeSet中仅有1个元素。原因是,HashSet是依赖hashCode和equals来判断的;而TreeSet是依赖compareTo来判断的。(细节请见BigDecimal的文档)
compareTo的用处除了我们可以直接使用外,很多API已经加以利用了,你只要提供具有内在排序能力(实现了Comparable接口)的对象就可以了,比如上面例子中的TreeSet。再例如,一个数组,如果放入数组的元素都是某个实现了Comparable接口的类的实例的话,那么给这个数组排序就可以简单到一句话:
Arrays.sort(myArray); // 使用Arrays的sort静态方法,其内部会使用实参的compareTo方法
【本章回顾】本章讲了作为所有类的超类的Object需要被子类改写的4个方法以及一个compareTo方法。作为最最基本的类——Object,可能也被认为是最最简单的,但是真正能够掌握其真谛的程序员可能并不多。尤其是对于要关心甚至是自己动手写“底层”代码的程序员来说,这一章读上三遍是很值得的。
【Effective Java 学习笔记】系列连载专题请见:
http://tonylian.iteye.com/categories/64208