如何实现普通对象的排序,比如按某个属性的大小比较?
如何实现普通对象(自定义类的对象)的排序,比如按某个属性的大小比较?
Java中的对象,正常情况下,只能进行比较:== 或 != (== 操作是比较的对象的引用地址是否相同,如果使用equals方法,Object类中有equals方法内部就是使用了==,自定义类可以重写equals方法)。不能使用 > 或 < 的但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
如何实现?Java中提供了两个接口: Comparable 或 Comparator
Comparable接口的使用举例: 自然排序
1.Java中的String类、包装类(Integer、Double、Short)等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。重写了compareTo()方法以后,就可以从小到大的排列
2. 重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
3. 对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序
由于String类实现了Comparable接口,实现了compareTo方法,所以可对String对象进行排序
//StringArray.java
package com.ylaihui.comparable;
import org.junit.Test;
import java.util.Arrays;
public class StringArray {
@Test
public void test1(){
String[] strs = new String[]{"yy","ll","aa","ii","hh","uu","ii"};
Arrays.sort(strs);
System.out.println(Arrays.toString(strs)); // [aa, hh, ii, ii, ll, uu, yy]
}
}
自定义类对象排序报异常ClassCastException
通过之前对sort方法的分析,我们发现,要排序某个自定义类的对象,需要用到compareTo方法,该方法是在Comparable接口中的,所以要想实现自定义类的对象的排序,需要实现Comparable接口中的compareTo方法,否则会报 ClassCastException异常。
//Person.java
package com.ylaihui.comparable;
public class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//PersonSort.java
package com.ylaihui.comparable;
import java.util.Arrays;
public class PersonSort {
public static void main(String[] args) {
Person[] people = new Person[4];
people[0] = new Person("yy",22);
people[1] = new Person("ll",23);
people[2] = new Person("aa",24);
people[3] = new Person("ii",25);
// ClassCastException: com.ylaihui.comparable.Person cannot be cast to java.lang.Comparable
Arrays.sort(people);
System.out.println(people);
}
}
自定义类对象的排序-自然排序
对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序
//Animal.java
package com.ylaihui.comparable;
public class Animal implements Comparable{
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Animal){
Animal animal = (Animal)o;
if(this.age > animal.age)
return 1;
else if(this.age < animal.age)
return -1;
else
return 0;
}else
throw new RuntimeException("类型不一致,无法比较");
}
}
//AnimalSort.java
package com.ylaihui.comparable;
import java.util.Arrays;
public class AnimalSort {
public static void main(String[] args) {
Animal[] animals= new Animal[4];
animals[0] = new Animal("yy",22);
animals[1] = new Animal("ll",23);
animals[2] = new Animal("aa",24);
animals[3] = new Animal("ii",25);
Arrays.sort(animals);
System.out.println("sort by age");
System.out.println(Arrays.toString(animals));
}
}
定制排序Comparator接口
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序
重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
//ComparatorTest.java
package com.ylaihui.comparable;
import java.util.Arrays;
import java.util.Comparator;
public class ComparatorTest {
public static void main(String[] args) {
Animal[] animals= new Animal[6];
animals[0] = new Animal("yy",22);
animals[1] = new Animal("ll",23);
animals[2] = new Animal("aa",24);
animals[3] = new Animal("aa",27);
animals[4] = new Animal("ii",28);
animals[5] = new Animal("hh",28);
// 创建了一个匿名子类的匿名对象
Arrays.sort(animals, new Comparator() {
@Override
// 按 age 从大到小排序
public int compare(Object o1, Object o2) {
if(o1 instanceof Animal && o2 instanceof Animal){
Animal a1 = (Animal) o1;
Animal a2 = (Animal) o2;
return -(a1.age - a2.age);
}else
throw new RuntimeException("类型不一致,无法比较");
}
});
System.out.println(Arrays.toString(animals));
}
}
//ComparatorTest1.java
package com.ylaihui.comparable;
import java.util.Arrays;
import java.util.Comparator;
public class ComparatorTest1 {
public static void main(String[] args) {
Animal[] animals= new Animal[6];
animals[0] = new Animal("yy",23);
animals[1] = new Animal("ll",23);
animals[2] = new Animal("aa",24);
animals[3] = new Animal("aa",27);
animals[4] = new Animal("ii",28);
animals[5] = new Animal("hh",28);
Arrays.sort(animals, new Comparator() {
@Override
// 按 age 从大到小排序,age相同,按name从大到小排序
public int compare(Object o1, Object o2) {
if(o1 instanceof Animal && o2 instanceof Animal){
Animal a1 = (Animal) o1;
Animal a2 = (Animal) o2;
if(a1.age == a2.age)
return -a1.name.compareTo(a2.name);
return -(a1.age - a2.age);
}else
throw new RuntimeException("类型不一致,无法比较");
}
});
System.out.println(Arrays.toString(animals));
}
}
Comparable接口与Comparator的区别
Comparable接口的方式一旦确定,保证Comparable接口实现类的对象在任何位置都可以比较大小,可多次使用。自然排序
Comparator接口属于临时性的比较,只能使用一次。定制排序