Java 클래스가 비슷한 것을 구현해야하는 이유는 무엇입니까?


답변:


212

실제 샘플은 다음과 같습니다. 그 참고 String도 구현을 Comparable.

class Author implements Comparable<Author>{
    String firstName;
    String lastName;

    @Override
    public int compareTo(Author other){
        // compareTo should return < 0 if this is supposed to be
        // less than other, > 0 if this is supposed to be greater than 
        // other and 0 if they are supposed to be equal
        int last = this.lastName.compareTo(other.lastName);
        return last == 0 ? this.firstName.compareTo(other.firstName) : last;
    }
}

나중..

/**
 * List the authors. Sort them by name so it will look good.
 */
public List<Author> listAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    Collections.sort(authors);
    return authors;
}

/**
 * List unique authors. Sort them by name so it will look good.
 */
public SortedSet<Author> listUniqueAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    return new TreeSet<Author>(authors);
}

15
나는 종종 당신이 당신의 메소드 와 일관성을 유지하기 위해 equals(그리고 따라서 hashCode) 재정의하기를 원한다는 것을 알고 싶다 compareTo. 예를 들어, 클래스가 a로 훌륭하게 재생되도록하려면이 작업이 필요합니다 TreeSet.
pidge

왜 단순히 돌아 오지 last않습니까?
Anirban Nag 'tintinmj'1

@ AnirbanNag'tintinmj '는 성이 동일한 경우 이름을 기준으로 자동 정렬합니다.
OddDev

compareTo가 int를 반환하는 이유와 그 의미에 대한 좋은 설명을 제공합니다. 가장 도움이됩니다.
james.garriss

1
@ user3932000 : 맞습니다. 모든 인터페이스의 요점입니다. 그러나 "기타 Java 메소드"에는 사용자가 작성한 메소드가 포함됩니다. 실제로 나는 대부분의 인터페이스가 사용자 코드에 의해 소비된다고 주장합니다. 더 큰 코드베이스에서 "자신은"신속하게 "다른 사람"이된다
Enno시오 지

40

비교는 자연 순서를 정의합니다. 이것이 의미하는 것은 하나의 객체가 "보다 작음"또는 "보다 큼"으로 간주되어야 할 때이를 정의한다는 것입니다.

여러 개의 정수가 있고 정렬하려고한다고 가정하십시오. 꽤 쉬운 방법입니다. 정렬 된 컬렉션에 넣으면됩니다.

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

그러나 이제 정렬이 의미가 있지만 정의되지 않은 사용자 정의 객체가 있다고 가정합니다. 인구 밀도가있는 우편 번호로 지구를 나타내는 데이터가 있고 밀도별로 정렬하려고한다고 가정 해 보겠습니다.

public class District {
  String zipcode; 
  Double populationDensity;
}

이제 그것들을 정렬하는 가장 쉬운 방법은 Comparable을 구현하여 자연스러운 순서로 정의하는 것입니다. 즉, 이러한 객체가 정렬되도록 정의 된 표준 방법이 있습니다. :

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

비교기를 정의하여 동등한 작업을 수행 할 수 있습니다. 차이점은 비교기 가 객체 외부의 순서 논리를 정의한다는 것 입니다. 별도의 프로세스에서 우편 번호로 동일한 객체를 주문해야합니다.이 경우 순서는 반드시 객체의 속성 일 필요는 없으며 객체의 자연 순서와 다릅니다. 외부 비교기를 사용하여 예를 들어 사전 순으로 정렬하여 정수에 대한 사용자 정의 순서를 정의 할 수 있습니다.

기본적으로 순서 논리는 어딘가에 존재해야합니다. 그것은 가능하다 -

  • 객체 자체에서 자연스럽게 비교 가능한 경우 (예 : 정수 확장)

  • 위의 예와 같이 외부 비교기에서 제공됩니다.


좋은 예이지만 TreeSet<Integer>대신 대신 TreeMap<Integer>해야합니다. 후자는 존재하지 않기 때문에 TreeMaps는 항상 <Key,Value>쌍입니다. Btw, TreeMap<District, Object>교육구가 Comparable을 구현 한 경우에만 가상의 효과 가 있을까요? 아직도 이해하려고 노력 중
phil294

14

javadoc에서 인용;

이 인터페이스는이를 구현하는 각 클래스의 객체에 총 정렬을 부과합니다. 이 순서를 클래스의 자연 순서라고하며 클래스의 compareTo 메소드를 자연 비교 방법이라고합니다.

이 인터페이스를 구현하는 객체의 목록 (및 배열)은 Collections.sort (및 Arrays.sort)로 자동 정렬 할 수 있습니다. 이 인터페이스를 구현하는 객체는 비교기를 지정할 필요없이 정렬 된 맵의 키 또는 정렬 된 세트의 요소로 사용할 수 있습니다.

편집 : .. 그리고 중요한 비트를 굵게 표시했습니다.


4
나는 당신이 대담한 문장 이후 의 문장 이 중요하지 않다고 말하고 싶습니다 .
Michael Borgwardt

8

클래스가 구현 Comparable한다는 것은 해당 클래스에서 두 개의 객체를 가져 와서 비교할 수 있다는 것을 의미합니다. 개체를 순서대로 정렬하는 특정 컬렉션 (컬렉션의 정렬 함수)과 같은 일부 클래스는 정렬하기 위해 어떤 개체가 "가장 큰"개체인지 알아야합니다.


8

위의 예제 대부분은 compareTo 함수에서 기존의 비교 가능한 객체를 재사용하는 방법을 보여줍니다. 같은 클래스의 두 객체를 비교할 때 고유 한 compareTo를 구현하려면 가격별로 정렬하려는 AirlineTicket 객체 (첫 번째 순위는 낮음)와 중간 기착 횟수 (더 적은 것은 1 위), 다음을 수행합니다.

class AirlineTicket implements Comparable<Cost>
{
    public double cost;
    public int stopovers;
    public AirlineTicket(double cost, int stopovers)
    {
        this.cost = cost; this.stopovers = stopovers ;
    }

    public int compareTo(Cost o)
    {
        if(this.cost != o.cost)
          return Double.compare(this.cost, o.cost); //sorting in ascending order. 
        if(this.stopovers != o.stopovers)
          return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
        return 0;            
    }
}

6

여러 필드 비교를 구현하는 쉬운 방법은 Guava의 ComparisonChain 을 사용하는 것입니다.

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

대신에

  public int compareTo(Person other) {
    int cmp = lastName.compareTo(other.lastName);
    if (cmp != 0) {
      return cmp;
    }
    cmp = firstName.compareTo(other.firstName);
    if (cmp != 0) {
      return cmp;
    }
    return Integer.compare(zipCode, other.zipCode);
  }
}

3

예를 들어 정렬 된 컬렉션 또는 을 원할 때


Fernando의 의미 : 정렬 된 컨테이너 클래스에 Comparable을 구현하는 "사물"을 저장하면 정렬 된 컨테이너 클래스가 자동으로 해당 "사물"을 주문할 수 있습니다.
Ian Durkan

2

Comparable은 클래스의 인스턴스를 비교하는 데 사용됩니다. 여러 가지 방법으로 인스턴스를 비교할 수 있으므로 인스턴스 compareTo를 비교하려는 방식을 파악하기 위해 메소드를 구현해야하는 이유가 있습니다 .

Dog 수업:

package test;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Main 수업:

package test;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

다음은 Java에서 비슷한 기능을 사용하는 좋은 예입니다.

http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2


2

Comparable인터페이스 를 구현할 때는 method 구현해야합니다 compareTo(). 예를 들어 ArrayList클래스의 정렬 방법을 사용하려면 객체를 비교해야합니다 . 정렬 할 수 있도록 개체를 비교할 수있는 방법이 필요합니다. 따라서 compareTo()클래스에 사용자 정의 메소드 가 필요 하므로 ArrayListsort 메소드 와 함께 사용할 수 있습니다 . 이 compareTo()메소드는 -1,0,1을 리턴합니다.

Java Head 2.0의 장을 읽었으며 여전히 배우고 있습니다.


1

좋아, 그러나 compareTo()비슷한 인터페이스를 구현하지 않고 메소드를 정의하는 것은 어떻습니까? 예를 들어, 클래스 City에 의해 정의의 nametemperature

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}

작동하지 않습니다. 비교 구현없이 - 나는 classcast 예외가
카란 Ahuja
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.