引言:在Java中提到比较二字,我们自然会想到equals()方法来比较两个数值是否相等,但这仅仅是对数值的操作,对其他数据类型就无法比较,因此用Comparator或者Comparable比较顺序(也就是排序)。
确定两个对象之间的大小关系及排列顺序称为比较,能实现这个比较功能的类或方法称之为比较器
首先,我们想要比较int类型的数,只需要两个数做差,如果差大于0,则a大于b;如果差小于0,则a小于b。
接下来再看一下String类型如何比较:
public class ComparableTest
{
public static void main(String[] args)
{
String a="A";
String b="B";
System.out.println(a.compareTo(b));
}
}
String类型我们无法a-b,但是Java提供了compareTo()方法来比较两个字符ASCII码大小,如果比较的数比被比较的数小返回-1
Output:
-1
接下来我们一起从Java提供的String类型的comparaTo()方法来探究一下Java的内部比较器结构。
首先进入compareTo()方法的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
}
return len1 - len2;
,返回了字符串ASCII码的差值,如果如果比较的数比被比较的数小返回-1,否则返回1,即, a.comparaTo(b) a小,返回-1 ,a大返回1。public interface Comparable<T> {
public int compareTo(T o);
}
继续看double类型如何比较大小:
public class ComparableTest
{
public static void main(String[] args)
{
double a=1.2;
double b=2.4;
System.out.println(((Double)a).compareTo((Double)b));
}
}
Output:
-1
问题:为什么我们要把double类型的a和b要转化为Double类型才能调用compareTo()方法呢?
首先,什么是Double(注意首字母大小写)?
我们知道了Double是一个类(包装类),那我们看一下源码:
public final class Double extends Number implements Comparable<Double> {
public int compareTo(Double anotherDouble) {
return Double.compare(value, anotherDouble.value);
}
}
本段代码中Comparable< Double>
说明与String类型一样,它是实现类中的方法,实现了Comparable< Double>接口。
在double类型比较时,相当于,我们把a和b转化成一个类的对象,去调用compareTo()方法。
上述是Java写好的对于特定数据类型的比较器,那我们在自己定义数据类型时,应当重写比较器。
模版:
Class B implements Comparable{
int comparaTo(B b){
//return的值按照需要排序的标准来写
return
}
}
举例:
public class Student implements Comparable{
String name;
int age;
public Student(){}
public Student(String name, int age)
{
super();
this.name = name;
this.age = age;
}
@Override
public int compareTo(Object o)
{
//按照年龄排序,即:a.ComparaTo(b)
//a来调用comparaTo()方法,方法的调用者用this表示
//b当作参数被传入compareTo(Object o),因此b为object类型,所以需要类型转换成student类才能使用age属性
Student stu=(Student) o;
return this.age - stu.age;
}
}
class Test{
public static void main(String []args) {
Student a = new Student("Ahana",18);
Student b = new Student("Babily",19);
System.out.println(a.compareTo(b));
}
}
Output:
-1
注意⚠️1:在写Student类时,要在public class Student 后加上implements Comparable,其中Comparable注意拼写!!!C为大写!!!!
注意⚠️2:在比较姓名时,直接用Java默认的compareTo()即可
return this.name compareTo( stu.name);
如果比较多不是一个属性该怎么办???比如我想先比较姓名,如果年龄一样,再比较年龄,该怎么办呐?
@Override
public int compareTo(Object o)
{
Student stu=(Student) o;
if( this.name.compareTo(stu.name) != 0) { //如果两者姓名一样,比较姓名,不一样,则比较年龄。
return this.name.compareTo(stu.name);
}else {
return this.age-stu.age;
}
}
OK,当我们的类实现了Comparable接口,那么类对象集合,或者数组可使用工具类进行排序。我们就可以使用Arrays.sort(数组,null),Collections.sort(集合,null)进行排序。
外部比较器常与匿名对象联系在一起
我们先看没有加入匿名对象的外部比较器
举例:
import java.util.Comparator;
public class Student {
String name;
int age;
public Student(){}
public Student(String name, int age)
{
super();
this.name = name;
this.age = age;
}
}
class OutsideComparator implements Comparator{
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
class OutsideComparator1 implements Comparator{
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据名字比较
return a1.name.compareTo(a2.name);
}
}
class Test{
public static void main(String []args) {
Student a = new Student("Ahana",18);
Student b = new Student("Babily",19);
OutsideComparator oc = new OutsideComparator();
int result = oc.compare(a, b);
System.out.println(result);
OutsideComparator oc1 = new OutsideComparator();
int result1 =oc1.compare(a, b);
System.out.println(result1)
}
}
Output:
-1
-1
注意事项⚠️:
import java.util.Comparator;
OutsideComparator oc = new OutsideComparator();
Comparator com = new OutsideComparator();
和Comparator com = new OutsideComparator1();
Comparator是接口,而OutsideComparator和OutsideComparator1则是实现类,com对象在调用compare()方法时,实际在调用实现类的方法,实则为多态的应用。 Comparator bj = new OutsideComparator(); //这里可以根据需求任意更改,可改成Comparator bj = new OutsideComparator1();
int result2 = bj.compare(a, b);
System.out.println(result2);
我们发现在写外部比较器时,对一个属性需要排序时要另外写一个class,还要创建对象,调用方法,相对比较麻烦,接下来介绍一种比较简单的方法:将匿名对象与外部比较器结合。
import java.util.Comparator;
class Test{
public static void main(String []args) {
Student a = new Student("Ahana",18);
Student b = new Student("Babily",19);
Comparator bj = new Comparator() { //匿名内部类需要通过父类或接口(Comparator)实现
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
};
int result = bj.compare(a, b);
System.out.println(result);
}
}
注意⚠️:格式
Comparator xxxx = new Comparator() {
public int compare(Object o1, Object o2)
{
return xxxxxx;
}
};
无需外加class了
升级版:
import java.util.Comparator;
class Test{
public static void main(String []args) {
Student a = new Student("Ahana",18);
Student b = new Student("Babily",19);
int res = new Comparator() {
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
}.compare(a, b);
System.out.println(res);
}
}
拆分解析一下
new Comparator() {
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
}
这段代码说,建立了一个Comparator的对象new Comparator() {……}
new Comparator() {
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
}.compare(a, b);
然后新建的对象调用compare(a, b);方法,new Comparator() {……}.compare(a, b);
int res = new Comparator() {
@Override
public int compare(Object o1, Object o2)
{
Student a1 =((Student)o1);
Student a2 =((Student)o2);
//根据年龄比较
return a1.age - a2.age;
}
}.compare(a, b);
本段代码,int res = new Comparator() {……}.compare(a, b); ,用int 类型res来接受返回的结果。
使用外部比较器还是外部比较器,由需求所决定,总而言之,外部比较器比内部比较器更灵活,更易维护。