此系列文章为本人对《Effective Java》一书的学习笔记,主要是记录对书中重点内容的理解。
既然有缘看到此文,那么希望能对你有所帮助。
本文对应原书第14条 考虑实现Comparable接口
原因
对于一个有排序需求的类,建议实现Comparable接口,因为这样可以让它轻松地被分类、搜索以及用在基于比较的集合中。
陈述
首先了解一下Comparable:它是一个带泛型的接口,且只有一个方法compareTo;
public interface Comparable<T> {
public int compareTo(T o);
}
当你实现了这个接口,重写了compareTo方法,这个类便可以很方便地利用Java自带的方法进行排序操作,如Arrays.sort方法。
Java中的所有值类和枚举类都实现了这个接口,值类实现Comparable接口的原因很简单,毕竟整天都在忙着比大小,作排序。而枚举类的这个实现相对冷门,我们来一起看一下:
打开java.lang.Enum,找到compareTo方法

这里我们可以看到,首先是把两个枚举的class进行了对比(这里不深究其对比逻辑),然后直接输出了ordinal之差。
看一下ordinal是什么:

说白了就是一个序号,这个序号怎么产生的呢,很简单,就是枚举在定义的时候顺序。
举个例子:
public enum Type {
A, // ordinal = 0
B, // ordinal = 1
C, // ordinal = 2
D; // ordinal = 3
}
所以Type.D.compareTo(Type.A)的返回值就是3 - 0 = 3。
虽然看起来有点意思,但是实际上有用吗?类的作者也考虑到了这一点,于是在注释上写了几笔:
The ordinal of this enumeration constant (its position in the enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this field. It is designed for use by sophisticated enum-based data structures, such as java.util.EnumSet and java.util.EnumMap.
简单来说就是,这玩意对绝大多数的码农来说没啥用,这个是设计给复杂的数据结构如EnumSet和EnumMap使用的。
规范
在重写compareTo方法时,作者建议我们使用装箱类型自带的compare方法来替代“>”和“<”,如:Double.compare和Short.compare,相对来说会更加简洁明朗。
作者提到,这本书的前两版是建议对于整数类型用“
>”和“<”比较,对于浮点型用compare方法。由于Java 7版本开始所有的装箱基本类型都有了compare方法,因此从第三版开始建议大家都使用compare。
另外书中作了一个引申,建议我们使用Compartor接口,因为可以更方便的进行一些操作,拿之前博客里面提到的PhoneNum举个例子:
public class PhoneNum implements Comparable<PhoneNum>{
/*区号*/
private Short areaCode;
/*号码*/
private Integer num;
/*分机号*/
private Integer extensionNum;
...
}
正常实现方式:
public int compareTo(PhoneNum other) {
int result = Short.compare(areaCode, other.areaCode);
if (result == 0) {
result = Integer.compare(num, other.num);
if (result == 0) {
result = Integer.compare(extensionNum, other.extensionNum);
}
}
return result;
}
用Compartor实现:
// 先构造一个静态的 Comparator
private static final Comparator<PhoneNum> COMPARATOR = Comparator
.comparingInt((PhoneNum pn) -> pn.areaCode)
.thenComparingInt(pn -> pn.num)
.thenComparingInt(pn -> pn.extensionNum);
public int compareTo(PhoneNum other) {
return COMPARATOR.compare(this, other);
}
如此,代码的质量肉眼可见提升了。
总结
对于一个有排序需求的类,为了让它可以轻松地进行分类、搜索以和用在基于比较的集合中,建议实现Comparable接口。在重写compareTo时,记得使用装箱基本类型自带的compare方法,对于逻辑较为复杂的逻辑,建议使用Comparator。
水平有限,若文章中存在错误,恳请不吝赐教,这对我以及后面的读者都有重要意义
本文分享了实现Comparable接口对排序类的重要性,讲解了compareTo方法的工作原理,推荐使用装箱类型自带的compare方法,并介绍了Comparator接口在复杂逻辑下的优势。通过PhoneNum实例演示了如何提升代码质量。
344

被折叠的 条评论
为什么被折叠?



