开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
12 Consider implementing Comparable 考虑实现Comparable接口
结论
- 实现Comparable接口的类表示可以做比较, 也就是可以进行排序. 所以并不是建议大家都去实现Comparable接口, 而是先想想自己的类是否有这样的需求. 有的话才建议实现接口.
- jdk中所有"值"相关的类都实现了Comparable接口, 比如Integer, String等.
- Comparable接口只有一个compareTo方法, 与equals方法有很多相似之处, 可以类比学习和使用.
- 个人体会: 实现Comparable接口并不是为了在代码中直接进行对象的比较, 而是为了方便在集合中进行排序操作.
实现方式
实现Comparable接口并重写compareTo接口, 方法定义如下, 入参是被比较对象. Comparable支持泛型, 所以可以在实现接口时指定比较对象类型, 相比于equals方法需要类型转换, compareTo要省事点. 返回结果为int类型, 规定返回0表示相等, 返回大于0的整数表示原对象大于比较对象, 返回小于0的整数表示原对象小于比较对象.
public int compareTo(T o);
需要遵守的约定和equals类似:
- 对称性, x.compareTo(y) == -y.compareTo(x)
- 传递性, x.compareTo(y) > 0 && y.compareTo(z) > 0 则x.compareTo(z) > 0. 特殊情况, x.compareTo(y) == 0 则对任意z, x.compareTo(z) == y.compareTo(z).
- 作者强烈建议: x.compareTo(y) == 0 时保证 x.equals(y) == true.
前两个好理解, 第三条难道不是强制要求么? 咬文嚼字的理解下, x.compareTo(y) == 0表示x和y的值相等, x.equals(y) == true 表示x对象和y对象相等. 区别在哪? 看一个jdk中的例子.
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("1.00");
System.out.println("equals result is = " + b1.equals(b2));
System.out.println("compareTo result is = " + b1.compareTo(b2));
// 结果
equals result is = false
compareTo result is = 0
上述例子中equals会考虑scale, scale不同所以两个对象不同, 但是compareTo只判断值是否相等. 注: 在BigDecimal中有两个概念scale和precision. scale表示小数点位数, precision表示有效数字的个数.
可能存在的问题.
由于存在compareTo和equals结果不同的情况, 所以会造成一些奇怪的现象, 还是以BigDecimal为例:
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("1.00");
HashMap<BigDecimal, String> hashMap = new HashMap<>();
TreeMap<BigDecimal, String> treeMap = new TreeMap<>();
hashMap.put(b1, "b1");
hashMap.put(b2, "b2");
treeMap.put(b1, "b1");
treeMap.put(b2, "b2");
System.out.println("hash map size is " + hashMap.size());
System.out.println("tree map size is " + treeMap.size());
// 结果
hash map size is 2
tree map size is 1
原理很简单, HashMap是通过equals和hashCode判断key是否重复, 而TreeMap是通过compareTo来判断的(保证插入数据的大小顺序). 由于对重复key判断标准不同, 导致最后map中包含了不同的元素个数.
总结
- 当我们构造的类有明显的"值"的概念, 那建议实现Comparable接口.
- 重写方法要遵守compareTo约定.
- 强烈建议保证compareTo和equals方法结果一致性, 否则可能造成未知异常.
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情