Comparable 및 Comparator를 사용하는 경우


108

필드에서 정렬해야하는 개체 목록이 있습니다 (예 : Score). 별다른 생각없이 Comparator를 구현하는 새로운 클래스를 작성했습니다.

이제 이것을 돌아 보면 Comparator를 구현하는 새 클래스를 만드는 대신 내 클래스가 Comparable을 구현해야하는지 궁금합니다. 점수는 개체가 정렬되는 유일한 필드입니다.

  1. 내가 실천으로 받아 들일 수있는 일을 한 것은 무엇입니까?

  2. 올바른 접근 방식은 "먼저 클래스가 Comparable (자연 순서를 위해)을 구현하도록하고 대체 필드 비교가 필요한 경우 Comparator를 구현하는 새 클래스를 만듭니다"입니까?

  3. 위의 (2)가 참이라면 Comparable 클래스를 구현 한 후에 만 ​​Comparator를 구현해야 함을 의미합니까? (원래 수업을 소유하고 있다고 가정).

답변:


80

나는 그것이 클래스를 정렬하는 명백한 자연스러운 방법이고, 누구든지 클래스를 정렬해야 할 필요가 있다면, 객체는 Comparable을 구현해야한다고 말하고 싶습니다.

그러나 정렬이 클래스의 비정상적인 사용이거나 정렬이 특정 사용 사례에서만 의미가 있다면 비교기가 더 나은 옵션입니다.

다른 말로, 클래스 이름이 주어지면 비교 가능한 정렬 방법이 분명합니까? 아니면 javadoc을 읽어야합니까? 후자의 경우 향후 모든 정렬 사용 사례에 비교기가 필요하며,이 시점에서 비교 가능을 구현하면 클래스 사용자의 속도를 높이 지 않고 속도를 늦출 수 있습니다.


간단한 예를 들어 주시겠습니까?
rgamber

좋은 예일 수 있습니다. gist.github.com/yclian/2627608 ComparableVersion을 사용하는 Version 클래스가 있습니다. 버전-객체로 간주되는 ComparableVersion 팩토리 메소드 제공 (정적 메소드 없음)-다른 버전과 비교할 수있는 버전을 제공합니다. 책임이 분리됩니다.
ses

2
당신은 참조 할 수 있습니다 java-journal.blogspot.in/2011/01/...
학습자

면접관이 Comparable로 동일한 작업을 수행 할 수 있는데 왜 Comparator를 사용하는지 물었습니다. 저는 멍청했습니다. :(
Aadam

@aLearner 링크가 죽었
G.Brown

127

문제가되는 개체 Comparable기본 (자연) 순서 지정 동작 을 정의하려는 경우 사용 합니다 . 일반적인 방법은이를 위해 개체의 기술 또는 자연 (데이터베이스?) 식별자를 사용하는 것입니다.

제어 가능한 외부 정렬 동작 Comparator을 정의하려는 경우 사용 합니다 . 기본 정렬 동작을 재정의 할 수 있습니다.


3
이는 기술적 인 설명이고 올바로 정확하지만 모범 사례에 대해서는 실제로 언급하지 않습니다.
extraneon

40
말하고 그 무엇, 즉 가장 좋은 방법이 아닌 경우 - 각 사용할 수 있나요?
Bozho 2010

1
"구현 Comparable 은 내가 자연의 질서를 정의한다는 것을 의미 ?" , 이것은 내가 찾고 있던 대답을주었습니다. 감사합니다 :)
소미

61

사용 Comparable:

  • 개체가 귀하의 통제에있는 경우.
  • 비교 행동이 주요 비교 행동 인 경우.

사용 Comparator:

  • 개체가 제어 범위 밖에 있고 구현할 수없는 경우 Comparable.
  • 기본 (으로 지정됨 Comparable) 동작 과 다른 동작을 비교하려는 경우 .

20

유사한 -java.lang.Comparable: int compareTo(Object o1)

비교 대상은 자신을 다른 대상과 비교할 수 있습니다. 클래스 자체는 인스턴스를 비교할 수 있도록 java.lang.Comparable 인터페이스를 구현해야합니다.

  • 현재 개체와 제공된 개체를 비교할 수 있습니다.
  • 이것을 사용하여 우리는 구현할 수 있습니다 only one sort sequence 하여 인스턴스 속성을 기반으로 있습니다. 전의:Person.id
  • String, Wrapper 클래스, Date, Calendar와 같은 미리 정의 된 클래스 중 일부는 Comparable 인터페이스를 구현했습니다.

비교기 -java.util.Comparator: int compare(Object o1, Object o2)

비교기 객체는 두 개의 다른 객체를 비교할 수 있습니다. 클래스는 인스턴스를 비교하지 않고 다른 클래스의 인스턴스를 비교합니다. 이 비교기 클래스는 java.util.Comparator 인터페이스를 구현해야합니다.

  • 동일한 유형의 두 개체를 비교할 수 있습니다.
  • 이를 사용 many sort sequence하여 인스턴스 속성을 기반으로 각각을 구현 하고 이름 을 지정할 수 있습니다. 전의:Person.id, Person.name, Person.age
  • 사용자 정의 정렬을 위해 사전 정의 된 클래스에 Comparator 인터페이스를 구현할 수 있습니다.

예:

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private int age;
    private long salary;

    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {       
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };

    public Employee() { }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.

    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }

    }   

    public static void main(String[] args) {

        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);

        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • 사용자 정의 정렬을 위해 우리는 비교기 @compare (o1, o2)로 이동합니다. 다른 시나리오에서는 비교기 @compareTo (o1)로 이동합니다. 하나 이상의 필드를 정렬하려면 코드를 변경하지 않고 비교기를 사용합니다.

를 들어 자바 8 람다 : 비교기는 내 게시물을 참조하십시오.


10

동일한 클래스의 인스턴스를 비교할 때 Comparable을 사용해야합니다.

비교기는 다른 클래스의 인스턴스를 비교하는 데 사용할 수 있습니다.

Comparable은 객체에 대한 자연스러운 순서를 정의해야하는 클래스에 의해 구현됩니다. Like String은 Comparable을 구현합니다.

다른 정렬 순서를 원할 경우 비교기를 구현하고 두 인스턴스를 비교하는 자체 방법을 정의 할 수 있습니다.


10

객체 정렬이 자연스러운 순서를 기반으로해야하는 경우 Comparable을 사용하고 다른 객체의 속성에 대해 정렬을 수행해야하는 경우 Java에서 Comparator를 사용하십시오.

Comparable과 Comparator의 주요 차이점 :

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence can be created   ¦ Many sort sequences can be created       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by:   ¦ Meant to be implemented to sort          ¦
¦ String, Wrapper classes, Date, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+

9

Comparator는 비교 가능한 모든 작업을 수행합니다.

| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you’re comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you’re comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes

다음과 같이 비교기를 익명 클래스로 사용하는 가장 좋은 방법을 찾았습니다.

private static void sortAccountsByPriority(List<AccountRecord> accounts) {
    Collections.sort(accounts, new Comparator<AccountRecord>() {

        @Override
        public int compare(AccountRecord a1, AccountRecord a2) {
            return a1.getRank().compareTo(a2.getRank());
        }
    });
}

정렬하려는 클래스 내에서 바로 이러한 메서드의 여러 버전을 만들 수 있습니다. 따라서 다음을 가질 수 있습니다.

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    기타...

이제 어디서나 이러한 정렬 방법을 사용하고 코드를 재사용 할 수 있습니다. 이것은 나에게 비교 가능한 모든 것을 제공하고 더 많은 것을 제공합니다 ... 그래서 나는 비교할 이유를 전혀 보지 못합니다.


8

내가 말할 것:

  • 비교가 직관적이라면 반드시 Comparable을 구현하십시오.
  • 비교가 직관적인지 확실하지 않은 경우 Comparator를 사용하면 더 명확하므로 코드를 유지해야하는 가난한 영혼에게 더 명확합니다.
  • 하나 이상의 직관적 인 비교가 가능하다면 비교기 (Comparator)를 선호합니다. 비교 대상 클래스의 팩토리 메소드로 빌드 할 수 있습니다.
  • 비교가 특수 목적인 경우 비교기를 사용하십시오.

6

다음 사항은 Comparable을 사용해야하는 상황과 Comparator를 사용해야하는 상황을 결정하는 데 도움이됩니다.

1) 코드 가용성

2) 단일 정렬 기준과 다중 정렬 기준

3) Arays.sort () 및 Collection.sort ()

4) SortedMap 및 SortedSet의 키로

5) 더 많은 수업과 유연성

6) 클래스 간 비교

7) 자연 질서

더 자세한 기사를 보려면 는 비교기를 사용할 때와 비교기를 사용할 때를


왜 아무도이 답변에 찬성하지 않는지 궁금합니다. 정말 좋은 것입니다. 한
Diganta

4
  • 클래스를 작성하는 순간 정렬의 사용 사례가 하나뿐이라면 Comparable을 사용하십시오.
  • 둘 이상의 정렬 전략이있는 경우에만 비교기를 구현하십시오.

4

자연스러운 순서 정렬이 필요한 경우-사용자 비교 가능 사용자 지정 순서 정렬이 필요한 경우-Comparator 사용

예:

Class Employee{
private int id;
private String name;
private String department;
}

자연 순서 정렬은 고유하므로 ID를 기반으로하고 사용자 지정 순서 정렬은 이름과 부서가됩니다.

Refrences :
클래스는 언제 Comparable 및 / 또는 Comparator 여야합니까? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

여기에 비슷한 질문이있었습니다. . 클래스는 언제 Comparable 및 / 또는 Comparator 여야합니까?

나는 다음과 같이 말할 것입니다. 예를 들어 내부 ID를 기반으로 자연스러운 순서와 같은 것을 위해 Comparable을 구현하십시오.

더 복잡한 비교 알고리즘 (예 : 여러 필드 등)이있는 경우 비교기를 구현합니다.


1
여러 필드에 대한 순서는 Comparable.
BalusC 2010

비교기와 비교기의 차이점은 java-journal.blogspot.in/2010/12/…
a Learner

2

비교 가능 :
동종 요소와 기본 자연 정렬 순서 만 저장하고 싶을 때마다 클래스 구현으로 이동할 수 있습니다. comparable 인터페이스를 .

비교기 :
동종 및 이종 요소를 저장하고 기본 맞춤 정렬 순서로 정렬하고 싶을 때마다 comparator인터페이스 로 이동할 수 있습니다.


0

내 필요는 날짜를 기준으로 정렬되었습니다.

그래서 나는 Comparable을 사용했고 그것은 나를 위해 쉽게 작동했습니다.

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

Comparable의 한 가지 제한은 목록 이외의 컬렉션에는 사용할 수 없다는 것입니다.


0

클래스를 소유하고 있다면 Comparable 로 가십시오 . 일반적으로 Comparator 는 클래스를 소유하고 있지 않지만 TreeSet 또는 TreeMap 을 사용해야하는 경우에 사용됩니다. ComparatorTreeSet 또는 TreeMap 의 conctructor에서 매개 변수로 전달할 수 있기 때문입니다. Comparator 및 Comparable 사용 방법은 http://preciselyconcise.com/java/collections/g_comparator.php 에서 확인할 수 있습니다 .


0

인터뷰 중 하나에서 nlogn 시간보다 더 나은 정확한 범위의 숫자를 정렬하라는 요청을 받았습니다. (카운팅 정렬을 사용하지 않음)

객체에 Comparable 인터페이스를 구현하면 암시 적 정렬 알고리즘이 재정의 된 compareTo 메서드를 사용하여 정렬 요소를 정렬 할 수 있으며 이는 선형 시간이됩니다.


0

Comparable은 숫자 값이 오름차순이고 문자열이 알파벳 순서 인 경우 제공되는 기본 자연 정렬 순서입니다. 예 :

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Comparator는 다음과 같은 비교 메소드를 재정 의하여 사용자 정의 myComparator 클래스에서 구현 된 사용자 정의 정렬 순서입니다.

Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]

-1

매우 간단한 접근 방식은 해당 엔티티 클래스가 데이터베이스에 표시되고 데이터베이스 테이블에 엔티티 클래스의 필드로 구성된 인덱스가 필요하다고 가정하는 것입니다. 대답이 '예'인 경우 비교 가능을 구현하고 자연 정렬 순서에 색인 필드를 사용합니다. 다른 모든 경우에는 비교기를 사용하십시오.


-2

구현을위한 내 주석 라이브러리 ComparableComparator:

public class Person implements Comparable<Person> {         
    private String firstName;  
    private String lastName;         
    private int age;         
    private char gentle;         

    @Override         
    @CompaProperties({ @CompaProperty(property = "lastName"),              
        @CompaProperty(property = "age",  order = Order.DSC) })           
    public int compareTo(Person person) {                 
        return Compamatic.doComparasion(this, person);         
    }  
}

더 많은 예를 보려면 링크를 클릭하십시오. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.