版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_39723544/article/details/83343778
一、引言
之前在一次机试时候,考察到了Java中比较。但是答得不是很好,加之最近在学习二叉树、红黑树这些,更不离不开比较、排序,所以在这里把Java中的比较好好总结下。
二、Comparable
1. 介绍
Comparable是一个接口,是一个内比较器(至于为什么说是内比较器,在第四节就会讲到这块)。简单来说,实现了Comparable接口的类可以实现自己和自己比较了。而具体的比较规则依赖于compareTo(T o)方法,而这种比较方式则又被称为自然比较法。
Collections.sort和Arrays.sort可以直接对实现了Comparable接口的类对象进行比较排序。
2. 核心代码
public interface Comparable<T> {
// 返回为int。分为以下三种情况:
// 返回值等于0,则表示相等
// 返回值大于0,则表示比较者大于被比较者
// 返回值小于0,则表示比较者小于被比较者
public int compareTo(T o);
}
3. 示例
public class ComparableDemo {
public static void main(String[] args) {
Student s1 = new Student("1110", "李四", "足球", 21);
Student s2 = new Student("1109", "张三", "篮球", 22);
Student s3 = new Student("1111", "王五", "排球", 23);
Student s4 = new Student("1112", "赵六", "乒乓球", 25);
System.out.println(s1.compareTo(s2));
System.out.println(s1.compareTo(s3));
List<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println("--------------排序前----------");
System.out.println(list);
Collections.sort(list);
System.out.println("--------------排序后----------");
System.out.println(list);
}
static class Student implements Comparable<Student>{
private String id;
private String name;
private String hobby;
private Integer age;
public Student() {}
public Student(String id, String name, String hobby, Integer age) {
this.id = id;
this.name = name;
this.hobby = hobby;
this.age = age;
}
@Override
public int compareTo(Student s) {
// 注意:这里其实调用的是String类的compareTo的方法,因为String也实现了Comparable接口
if (id.compareTo(s.getId()) > 0) {
return 1;
} else if (id.compareTo(s.getId()) == 0) {
return 0;
}
return -1;
}
// 省略get、set方法
}
}
运行结果如下:
三、Comparator
1. 介绍
Comparator同样也是一个接口,是一个外比较器。
2. 核心代码
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
// 省略其他接口中默认实现的方法
}
3. 使用场景
- 类虽然已实现Comparable接口,但是我对他的比较规则不满意,我想根据我自己的业务情况重新定义比较规则。这时候可以使用匿名内部的方式来达到我们的目的。
- 某个类我们手里只有字节码文件(拿不到源代码),不管这个类没有实现Comparable接口,我们可以通过Comparator接口达到比较的目的。
4. 示例(三种变体写法)
基础写法:
public static void main(String[] args) {
Student s1 = new Student("1110", "李四", "足球", 29);
Student s2 = new Student("1110", "赵六", "篮球", 22);
Student s3 = new Student("1110", "李四", "排球", 23);
Student s4 = new Student("1110", "赵六", "乒乓球", 25);
List<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println("--------------排序前----------");
System.out.println(list);
Collections.sort(list, new Comparator<Student>() {
// 按照id,name及age比较排序。
@Override
public int compare(Student o1, Student o2) {
if (o1.getName().equals(o2.getName())) {
if (o1.getName().equals(o2.getName())) {
return o1.getAge().compareTo(o2.getAge());
}
return o1.getName().compareTo(o2.getName());
}
return o1.getName().compareTo(o2.getName());
}
});
System.out.println("--------------排序后----------");
System.out.println(list);
}
static class Student implements Comparable<Student>{
private String id;
private String name;
private String hobby;
private Integer age;
public Student() {}
public Student(String id, String name, String hobby, Integer age) {
this.id = id;
this.name = name;
this.hobby = hobby;
this.age = age;
}
@Override
public int compareTo(Student s) {
// 注意:这里其实调用的是String类的compareTo的方法,因为String也实现了Comparable接口
if (id.compareTo(s.getId()) > 0) {
return 1;
} else if (id.compareTo(s.getId()) == 0) {
return 0;
}
return -1;
}
// 省略get、set方法
}
结果如下:
变体写法1:
// 显示创建比较器类
static class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
if (o1.getName().equals(o2.getName())) {
if (o1.getName().equals(o2.getName())) {
return o1.getAge().compareTo(o2.getAge());
}
return o1.getName().compareTo(o2.getName());
}
return o1.getName().compareTo(o2.getName());
}
}
// 在main方法中这样调用
public static void main(String[] args) {
Student s1 = new Student("1110", "李四", "足球", 29);
Student s2 = new Student("1110", "赵六", "篮球", 22);
Student s3 = new Student("1110", "李四", "排球", 23);
Student s4 = new Student("1110", "赵六", "乒乓球", 25);
List<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println("--------------排序前----------");
System.out.println(list);
// 注意看这里:如果理解匿名内部类的话,这里应该很容易理解。
StudentComparator sc = new StudentComparator();
Collections.sort(list, sc);
System.out.println("--------------排序后----------");
System.out.println(list);
}
变体写法2:
四、比较
1. 相同点
二者都是接口,而且都可以实现比较,进而实现排序。
2. 不同点
- Comparable接口的耦合性较强一些,必须要在类的源代码里面进行修改。
- 而Comparator接口则灵活性强一些,它可以在我们没有源代码的情况下,可以实现我们自定义的排序规则。
五、总结
其实具体在开发中使用哪一种接口,还是根据具体情况,选择最合适的方式进行实现。