나는 비교기를 사용하는 방법을 배웠지 만 비교기에 어려움을 겪고 있습니다. 내 코드에 오류가 있습니다.
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));
}
}
}
나는 그것이 비교 방법으로 캐스팅과 관련이 있다고 생각하지만 그것을 가지고 놀고 있었고 여전히 해결책을 찾지 못했습니다.
답변
예제 클래스에는 몇 가지 어색한 것들이 있습니다.
- 그것이있는 동안은 사람들이라고
price
하고info
(객체가 아닌 사람들을 위해 뭔가 더); - 클래스를 복수의 것으로 명명 할 때, 그것은 하나 이상의 것을 추상화 한 것입니다.
어쨌든 다음은 사용 방법에 대한 데모입니다 Comparator<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);
}
}
답변
다음은 정렬을 바로 수행 할 수있는 매우 짧은 템플릿입니다.
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 (meaning the order stays the same)
}
});
기억하기 어려운 경우 다음과 유사하다는 것을 기억하십시오 (숫자 부호의 관점에서).
lhs-rhs
가장 작은 숫자에서 큰 숫자까지 오름차순으로 정렬하려는 경우입니다.
답변
People implements Comparable<People>
대신 사용하십시오 . 이것은의 자연 순서를 정의합니다 People
.
A Comparator<People>
도 추가로 정의 할 수 있지만 People implements Comparator<People>
작업을 수행하는 올바른 방법은 아닙니다.
에 대한 두 가지 과부하 Collections.sort
가 다릅니다.
<T extends Comparable<? super T>> void sort(List<T> list)
Comparable
자연스러운 순서대로 객체를 정렬 합니다
<T> void sort(List<T> list, Comparator<? super T> c)
- 호환 가능한 것을 사용하여 무엇이든 정렬
Comparator
- 호환 가능한 것을 사용하여 무엇이든 정렬
당신은 정렬 시도하여 두 가지를 혼동하고 Comparator
(그것이 의미가하지 않는 이유를 다시이다 Person implements Comparator<Person>
). 다시 사용하려면 Collections.sort
다음 중 하나에 해당해야합니다.
- 유형이어야합니다
Comparable
(사용하는 1-ARGsort
) Comparator
유형에 대한 A 를 제공해야합니다 (2-args 사용sort
).
관련 질문
또한 새 코드에서 원시 유형을 사용하지 마십시오 . 원시 유형은 안전하지 않으며 호환성을 위해서만 제공됩니다.
즉, 이것 대신에 :
ArrayList peps = new ArrayList(); // BAD!!! No generic safety!
다음과 같이 typesafe 일반 선언을 사용해야합니다.
List<People> peps = new ArrayList<People>(); // GOOD!!!
그러면 코드가 컴파일되지 않는다는 것을 알게 될 것입니다 !! 코드에 문제가 있기 때문에 ( Person
하지 않습니다 implements Comparable<Person>
), 그러나 원시 유형을 사용했기 때문에 컴파일러는 이것을 확인하지 않고 대신 ClassCastException
런타임에 얻 습니다!
이것은 항상 새로운 코드에서 타입 안전 제네릭 형식을 사용하도록 설득해야합니다. 항상.
또한보십시오
답변
완전성을 위해 간단한 단일 라이너 compare
방법이 있습니다.
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person lhs, Person rhs) {
return Integer.signum(lhs.getId() - rhs.getId());
}
});
답변
자바 8은 쓰기에있는 코드의 양을 감소 비교기 만드는 새로운 방법이 추가 Comparator.comparing을 . 또한 Comparator를 확인하십시오.
여기 샘플이 있습니다
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class ComparatorTest {
@Test
public void test() {
List<Person> peopleList = new ArrayList<>();
peopleList.add(new Person("A", 1000));
peopleList.add(new Person("B", 1));
peopleList.add(new Person("C", 50));
peopleList.add(new Person("Z", 500));
//sort by name, ascending
peopleList.sort(Comparator.comparing(Person::getName));
assertTrue(peopleList.get(0).getName().equals("A"));
assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("Z"));
//sort by name, descending
peopleList.sort(Comparator.comparing(Person::getName).reversed());
assertTrue(peopleList.get(0).getName().equals("Z"));
assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("A"));
//sort by age, ascending
peopleList.sort(Comparator.comparing(Person::getAge));
assertTrue(peopleList.get(0).getAge() == 1);
assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1000);
//sort by age, descending
peopleList.sort(Comparator.comparing(Person::getAge).reversed());
assertTrue(peopleList.get(0).getAge() == 1000);
assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1);
}
class Person {
String name;
int age;
Person(String n, int a) {
name = n;
age = a;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
}
답변
Comparator가 아닌 Comparable을 구현하려고합니다. compareTo 메소드를 구현해야합니다. 그래도 가까이에 있습니다. 비교기는 “타사”비교 루틴입니다. 이 개체는 다른 개체와 비교할 수 있습니다.
public int compareTo(Object obj1) {
People that = (People)obj1;
Integer p1 = this.getId();
Integer p2 = that.getid();
if (p1 > p2 ){
return 1;
}
else if (p1 < p2){
return -1;
}
else
return 0;
}
참고로 여기에서 getId ..에 대한 null을 확인하는 것이 좋습니다.
답변
다음은 Comparable을 반환하는 제로 arg 메서드에서 작동하는 Comparator의 예입니다. jdk 또는 라이브러리에 이와 같은 것이 있습니까?
import java.lang.reflect.Method;
import java.util.Comparator;
public class NamedMethodComparator implements Comparator<Object> {
//
// instance variables
//
private String methodName;
private boolean isAsc;
//
// constructor
//
public NamedMethodComparator(String methodName, boolean isAsc) {
this.methodName = methodName;
this.isAsc = isAsc;
}
/**
* Method to compare two objects using the method named in the constructor.
*/
@Override
public int compare(Object obj1, Object obj2) {
Comparable comp1 = getValue(obj1, methodName);
Comparable comp2 = getValue(obj2, methodName);
if (isAsc) {
return comp1.compareTo(comp2);
} else {
return comp2.compareTo(comp1);
}
}
//
// implementation
//
private Comparable getValue(Object obj, String methodName) {
Method method = getMethod(obj, methodName);
Comparable comp = getValue(obj, method);
return comp;
}
private Method getMethod(Object obj, String methodName) {
try {
Class[] signature = {};
Method method = obj.getClass().getMethod(methodName, signature);
return method;
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
private Comparable getValue(Object obj, Method method) {
Object[] args = {};
try {
Object rtn = method.invoke(obj, args);
Comparable comp = (Comparable) rtn;
return comp;
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
}