[重学Java基础][类与接口][Part.1]Comparable接口与Comparator比较器类
前言
Java中有许多类都带有比较或者排序功能
例如Java 8 后在List的接口中添加的默认方法sort
default void sort(Comparator
Comparable 可比较接口
源码很简单 只有一个比较方法compareTo(T o)
public interface Comparable<T> {
public int compareTo(T o);
}
Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现
若一个类实现了Comparable 接口,则许多调用排序的方法可以不用显示的指定比较器
会默认调用类已经实现的比较接口的比较法则
public class Staff implements Comparable<Staff> {
private Integer age;
private String name;
private String id;
private String depart;
private Integer level;
……
@Override
public int compareTo(Staff o) {
if(this==o)
{
return 0;
}
if (this.level > o.level) {
return 1;
} else if (this.level < o.level) {
return -1;
}
else {
return 0;
}
}
}
Staff 类实现了Comparable接口 实现了compareTo方法
注意 Java 8后 升级了排序比较算法
比较处理法则 必须满足 大于返回正数 小于返回负数 等于返回0
不能再仅有大于和小于两种情况的处理结果
因此staff类可以被排序
Staff[] staffs=……
Arrays.sort(staffs);
测试代码
Staff lilith=new Staff();
lilith.setName("LilithBristol");
lilith.setAge(18);
lilith.setLevel(3);
Staff Jolieye=new Staff();
Jolieye.setName("JolieyeSigtuna");
Jolieye.setAge(17);
Jolieye.setLevel(2);
List<Staff> staffList=new ArrayList<>(5);
staffList.add(lilith);
staffList.add(Jolieye);
System.out.println(staffList);
Collections.sort(staffList);
System.out.println(staffList);
结果
[Staff{age=18, name='LilithBristol', id='null', depart='null', level=3}, Staff{age=17, name='JolieyeSigtuna', id='null', depart='null', level=2}]
[Staff{age=17, name='JolieyeSigtuna', id='null', depart='null', level=2}, Staff{age=18, name='LilithBristol', id='null', depart='null', level=3}]
在《Effective Java》中,作者就推荐在编写自己的类的时候 尽可能的实现Comparable接口,因为如果实现了Comparable接口,就可以调用许多依赖此接口的泛型方法和工具类,只有很小的开销却获得了十分强大的功能。
因此,所有Java平台类库中的存储数据结构都实现了Comparable接口。如果你自定义的类具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者,那你就应该考虑实现这个接口。
Comparator比较器
对于一个已存在的不能活或者不好变更的类 你也想要进行比较的情况
一个类已经有了默认的比较法则 而你需要一个不同的比较方式的情况
可以使用比较器 Comparator
public interface Comparator
相比Comparable接口 Comparator比较器的源码可就复杂多了
但细看后发现 增加的大部分是Java8 默认方法 用于处理流中的比较
int compare(T var1, T var2);
boolean equals(Object var1);
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator)((Serializable)((c1, c2) -> {
int res = this.compare(c1, c2);
return res != 0 ? res : other.compare(c1, c2);
}));
}
default <U> Comparator<T> thenComparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) {
return this.thenComparing(comparing(keyExtractor, keyComparator));
}
default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T, ? extends U> keyExtractor) {
return this.thenComparing(comparing(keyExtractor));
}
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
return this.thenComparing(comparingInt(keyExtractor));
}
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
return this.thenComparing(comparingLong(keyExtractor));
}
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
return this.thenComparing(comparingDouble(keyExtractor));
}
static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
return Collections.reverseOrder();
}
static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
return NaturalOrderComparator.INSTANCE;
}
static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
return new NullComparator(true, comparator);
}
static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
return new NullComparator(false, comparator);
}
static <T, U> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) {
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator)((Serializable)((c1, c2) -> {
return keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2));
}));
}
static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator)((Serializable)((c1, c2) -> {
return ((Comparable)keyExtractor.apply(c1)).compareTo(keyExtractor.apply(c2));
}));
}
static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator)((Serializable)((c1, c2) -> {
return Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}));
}
static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator)((Serializable)((c1, c2) -> {
return Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
}));
}
static <T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator)((Serializable)((c1, c2) -> {
return Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
}));
}
使用比较器 普通情况下只需重写int compare(T var1, T var2)方法即可
Staff lilith=new Staff();
lilith.setName("LilithBristol");
lilith.setAge(18);
lilith.setLevel(3);
Staff Jolieye=new Staff();
Jolieye.setName("JolieyeSigtuna");
Jolieye.setAge(17);
Jolieye.setLevel(2);
Staff tuzi=new Staff();
tuzi.setName("tuzi");
tuzi.setAge(28);
List<Staff> staffList=new ArrayList<>(5);
staffList.add(lilith);
staffList.add(Jolieye);
staffList.add(tuzi);
System.out.println(staffList);
Collections.sort(staffList,new Comparator<Staff>() {
@Override
public int compare(Staff o1, Staff o2) {
if (x == y) {
return 0;
}
if (x.getAge() > y.getAge()) {
return 1;
} else if (x.getAge().equals(y.getAge())) {
return 0;
}else {
return -1;
}
}
});
System.out.println(staffList);
结果
[Staff{age=18, name='LilithBristol', id='null', depart='null', level=3}, Staff{age=17, name='JolieyeSigtuna', id='null', depart='null', level=2}, Staff{age=28, name='tuzi', id='null', depart='null', level=null}]
[Staff{age=17, name='JolieyeSigtuna', id='null', depart='null', level=2}, Staff{age=18, name='LilithBristol', id='null', depart='null', level=3}, Staff{age=28, name='tuzi', id='null', depart='null', level=null}]
此处就使用了比较器Comparator 传入了一种完全不同的比较法则
总结
Comparable 是比较接口,调用时必须继承接口,和一个具体类相绑定,
而Comparator 比较灵活,它可以被用于各个需要比较功能的类使用。
可以说前者属于静态绑定,而后者可以动态设定。
也可以把 Comparable 称为 “内部比较器”,而 Comparator 称为 “外部比较器”。