如何在Java中使用Comparator进行排序

问题

我学会了如何使用可比较的,但我对比较器有困难。我的代码中有错误:

Exception in thread "main" java.lang.ClassCastException: New.People cannot be cast to java.lang.Comparable
 at java.util.Arrays.mergeSort(Unknown Source)
 at java.util.Arrays.sort(Unknown Source)
 at java.util.Collections.sort(Unknown Source)
 at New.TestPeople.main(TestPeople.java:18)

这是我的代码:

import java.util.Comparator;

public class People implements Comparator {
   private int id;
   private String info;
   private double price;

   public People(int newid, String newinfo, double newprice) {
       setid(newid);
       setinfo(newinfo);
       setprice(newprice);
   }

   public int getid() {
       return id;
   }

   public void setid(int id) {
       this.id = id;
   }

   public String getinfo() {
       return info;
   }

   public void setinfo(String info) {
       this.info = info;
   }

   public double getprice() {
       return price;
   }

   public void setprice(double price) {
       this.price = price;
   }

   public int compare(Object obj1, Object obj2) {
       Integer p1 = ((People) obj1).getid();
       Integer p2 = ((People) obj2).getid();

       if (p1 > p2) {
           return 1;
       } else if (p1 < p2){
           return -1;
       } else {
           return 0;
       }
    }
}
import java.util.ArrayList;
import java.util.Collections;

public class TestPeople {
    public static void main(String[] args) {
        ArrayList peps = new ArrayList();

        peps.add(new People(123, "M", 14.25));
        peps.add(new People(234, "M", 6.21));
        peps.add(new People(362, "F", 9.23));
        peps.add(new People(111, "M", 65.99));
        peps.add(new People(535, "F", 9.23));

        Collections.sort(peps);

        for (int i = 0; i < peps.size(); i++){
            System.out.println(peps.get(i));
        }
    }
}

我相信它必须在比较方法中对铸造做一些事情,但我正在玩它仍然无法找到解决方案


#1 热门回答(182 赞)

你的示例类有几个尴尬的事情:

  • 它被称为人,虽然它有价格和信息(更多的东西对象,而不是人);
  • 当将一个类命名为复数时,它表明它是一个不止一件事的抽象。

无论如何,这是一个如何使用aComparator<T>的演示:

public class ComparatorDemo {

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Joe", 24),
                new Person("Pete", 18),
                new Person("Chris", 21)
        );
        Collections.sort(people, new LexicographicComparator());
        System.out.println(people);
        Collections.sort(people, new AgeComparator());
        System.out.println(people);
    }
}

class LexicographicComparator implements Comparator<Person> {
    @Override
    public int compare(Person a, Person b) {
        return a.name.compareToIgnoreCase(b.name);
    }
}

class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person a, Person b) {
        return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
    }
}

class Person {

    String name;
    int age;

    Person(String n, int a) {
        name = n;
        age = a;
    }

    @Override
    public String toString() {
        return String.format("{name=%s, age=%d}", name, age);
    }
}

##编辑

等效的Java 8演示如下所示:

public class ComparatorDemo {

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Joe", 24),
                new Person("Pete", 18),
                new Person("Chris", 21)
        );
        Collections.sort(people, (a, b) -> a.name.compareToIgnoreCase(b.name));
        System.out.println(people);
        Collections.sort(people, (a, b) -> a.age < b.age ? -1 : a.age == b.age ? 0 : 1);
        System.out.println(people);
    }
}

#2 热门回答(115 赞)

这是一个超短的模板,可以立即进行排序:

Collections.sort(people,new Comparator<Person>(){
   @Override
   public int compare(final Person lhs,Person rhs) {
     //TODO return 1 if rhs should be before lhs 
     //     return -1 if lhs should be before rhs
     //     return 0 otherwise
     }
 });

如果难以记住,请尽量记住它与类似的符号(就数字的符号而言):

lhs-rhs

如果你想按升序排序:从最小数字到最大数字。


#3 热门回答(32 赞)

UsePeople implements Comparable<People>instead;这定义了People的自然顺序。

AComparator<People>也可以另外定义,但是People implements Comparator<People>不是正确的做事方式。

Collections.sort的两个重载不同:

  • <T延伸可比较<? super T >> void sort(List <T> list)使用自然顺序对Comparable对象进行排序
  • <T> void sort(List <T> list,Comparator <?super T> c)使用兼容的Comparator对任何内容进行排序

你通过尝试排序aComparator来混淆两者(这也是为什么它没有意义的Person implements Comparator<Person>)。同样,要使用Collections.sort,你需要其中一个为真:

  • 类型必须是Comparable(使用1-arg排序)
  • 必须提供该类型的比较器(使用2-args排序)

###相关问题

  • 何时使用Comparable vs Comparator
  • 排序联系​​人的ArrayList

此外,不使用新代码中的原始类型。原始类型是不安全的,并且它仅提供兼容性。

也就是说,而不是这个:

ArrayList peps = new ArrayList(); // BAD!!! No generic safety!

你应该使用这样的类型安全泛型声明:

List<People> peps = new ArrayList<People>(); // GOOD!!!

然后你会发现**你的代码甚至没有编译!!**这将是一件好事,因为代码有问题(Person不是implements Comparable<Person>),但是因为你使用了原始类型,编译器没有检查这个,而是你获得aClassCastExceptionat运行时!!!

这应该说服你始终在新代码中使用类型安全泛型类型。总是。

也可以看看

  • 什么是原始类型,为什么我们不应该使用它?