1.前言
我们经常使用>,<,=等运算符来比较数与数之间的大小关系,但显然这些运算符并不同样适用于对象.但如果需要比较对象,那么我们应该怎么办呢?
我们可以考虑两种方法 : (1) 自然排序 (2). 定制排序.
2.自然排序(实现Comparable接口)
(1). 为什么String类的对象可以进行比较大小,正是因为String类实现了Comparable接口,并重写了comparaTo(Object o)方法.
(2). 操作步骤
- 设计类实现Comparable接口
- 重写compareTo(Object o)方法.在此方法中指明对象比较的标准.
- 创建类的多个实例,调用Arrays.sort()方法比较.
(3). 例 :
public class Phone implements Comparable{
private String name;
private double price;
public Phone() {
}
public Phone(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public int compareTo(Object o) {
if (this == o) {
return 0;
}
if (o instanceof Phone) {
Phone p = (Phone) o;
return Double.compare(this.price, p.price);
}
throw new RuntimeException();
}
@Override
public String toString() {
return "Phone{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
public class PhhoneTest {
public static void main(String[] args) {
Phone[] p1 = new Phone[5];
p1[0] = new Phone("xiaomi", 4900);
p1[1] = new Phone("vivo", 5900);
p1[2] = new Phone("oppo", 6900);
p1[3] = new Phone("huawei", 7900);
p1[4] = new Phone("iPhone", 8900);
Arrays.sort(p1);
for (int i = 0; i < p1.length; i++) {
System.out.println(p1[i].toString());
}
}
}
控制台
Phone{name='xiaomi', price=4900.0}
Phone{name='vivo', price=5900.0}
Phone{name='oppo', price=6900.0}
Phone{name='huawei', price=7900.0}
Phone{name='iPhone', price=8900.0}
上面代码实现了price为标准实现了对象之间的比较.如果我们需要以name为标准我们应该怎么办呢?
只需要修改具体类(Phone)中重写的compareTo(Object o)方法.
@Override
public int compareTo(Object o) {
if (this == o) {
return 0;
}
if (o instanceof Phone) {
Phone p2 = (Phone) o;
return p1.getName().compareTo(p2.getName());
}
throw new RuntimeException();
}
控制台
Phone{name='huawei', price=7900.0}
Phone{name='iPhone', price=8900.0}
Phone{name='oppo', price=6900.0}
Phone{name='vivo', price=5900.0}
Phone{name='xiaomi', price=4900.0}
return语句中调用了String类重写的compareTo(Object o)方法.比较字符串对象大小.如果左边字符串比右边的小,返回负数.如果左边的比右边的大,返回正数.如果相等,返回0.上文Double.compare(double a,double b)方法同理.
3.定制排序(实现Comparator接口)
(1). 思考
- 当元素所属的类没有实现java.lang.Comparable接口并且不方便修改时.
- 如果一个类实现了Comparable接口,也指定了两个对象的比较规则,但我们不想按照它预定义的方式去比较对象,而且我们不能随意修改,那我们应该怎么办呢?
- 如String[] s =new String[10];//静态初始化;Arrays.sort(s)是将字符串从小到大排序完毕,但我们期望将字符串从大到小排序,但我们不能随意修改String类中的源码,我们应该怎么办呢?
(2). 我们可以增加java.util.Comparator接口,强制按照我们想要的方式去比较对象.
- 重写Conpare(Object o1, Object o2)方法,比较二者的大小.
- 将Comparator接口的实现类的对象作为参数传入到sort方法中,从而允许以自己想要的方式进行排序.
(3). 例 : 以字符串为比较的依据进行对象的比较.此处使用匿名实现类的匿名对象更为方便.如果想以price作为比较的依据,只需改动Compare(Object o1, Object o2)方法即可.
public class PhhoneTest {
public static void main(String[] args) {
Phone[] p1 = new Phone[5];
p1[0] = new Phone("xiaomi", 4900);
p1[1] = new Phone("vivo", 5900);
p1[2] = new Phone("oppo", 6900);
p1[3] = new Phone("huawei", 7900);
p1[4] = new Phone("iPhone", 8900);
Arrays.sort(p1, new Comparator<Phone>() {
@Override
public int compare(Phone o1, Phone o2) {
if (o1 == o2) {
return 0;
}
if (o1 instanceof Phone && o2 instanceof Phone) {
Phone a = (Phone) o1;
Phone b = (Phone) o1;
return a.getName().compareTo(b.getName());
}
throw new RuntimeException();
}
});
for (int i = 0; i < p1.length; i++) {
System.out.println(p1[i].toString());
}
}
}
4.两种方式的比较
(1).
自然排序比较单一,唯一.
定制排序比较灵活,多样.
(2).
自然排序是一劳永逸的.
定制排序是临时的.
(3).
自然排序对应的接口类型是Comparable,重写的是CompareTo(Object o)方法.
定制排序对应的接口类型是Comparator,重写的是Compare(Object o1, Object o2)方法
注意到为什么CompareTo方法的形参有一个,而Compare方法有两个.
很简单,因为this对象(该方法的调用者)跟传入方法的对象的类型相同,都是具体类(如上的Phone),而compareTo方法的this跟具体类的对象并无关系,充当传入sort方法的参数,所以将两个需要比较的对象都传入到Compare方法中.