Item14는 Comparable Interface의 메서드인 compareTo()에 대한 내용을 다룬다.
compareTo 메서드는 Object의 메서드가 아닌 Comparable 메서드이며 두가지만 빼면 Object 클래스의 equals와 같다.
compareTo 메서드는 단순 동치성 비교에 더해 순서까지 비교할 수 있고, 제네릭하다.
Comparable를 구현했다는 것은 해당 클래스의 인스턴스들에는 순서가 있음을 뜻한다.
따라서 Comparable 를 구현한 객체들의 배열은 손쉽게 정렬 가능하다
Arrays.sort(arrays)
Comparable을 구현하면 다양한 기능을 누릴 수 있다.
자바 라이브러리의 모든 값 클래스, 열거형 타입은 Comparable을 구현했다.
순서가 명확한 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현하라.
public interface Comparable<T> {
public int compareTo(T o);
}
실제 Comparable interface 는 다음과 같이 선언 되어 있다.
compareTo 메서드의 규약은 다음과 같다 ( equals의 규약과 비슷 )
해당 객체가 파라미터로 넘어온 객체보다 작으면 음의 정수(-1)을 , 같다면(0) , 크다면 양의정수(1) 정수를 반환한다. 만약 해당 객체와 비교할 수 없다면 ClassCastException을 발생한다.
- Comparable를 구현한 클래스는 모든 x,y에 대해서 x.compareTo(y) == -(y.compareTo(x))여야 한다
- Comparable를 구현한 클래스는 추이성을 보장해야한다. x.compareTo(y) > 0 이고 y.compareTo(z) > 0 이라면 x.compareTo(z)도 0보다 커야한다.
- Comparable를 구현한 클래스는 모든 z에 대해 x.compare(y) == 0이라면 x.compareTo(z)와 y.compareTo(z)는 같아야 한다.
- x.compareTo(y) == 0 이라면 x.equals(y)도 true여야 한다.
첫번째 규약
두 객체의 참조 순서를 바꿔도 같은 결과가 나와야 한다는 이야기이다.
첫번째 객체가 두번째 객체가 크다면 , 두번째가 첫번째보다 작아야한다.
첫번째 객체가 두번째 객체보다 작다면, 두번째 객체가 첫번째 객체보다 커야 한다.
첫번째 객체와 두번째 객체가 같다면, 두번재 객체와 첫번째 객체는 같아야한다.
어떻게 보면 당연한 이야기이다.
두번째 규약
X객체가 Y보다 크고 Y객체가 Z객체보다 크다면 X객체는 Z객체보다 커야한다.
세번째 규약
X객체와 Y객체가 같다면 x.compareTo(z)와 y.compareTo(y)의 결과는 같아야 한다.
네번째 규약
이 규약은 필수는 아니지만 꼭 지키길 권장하는 규약이다. 한마디로 compareTo 메서드로 수행한 동치성 결과는 equals의 결과와 같아야한다는 말이다.
Collection, Set or Map 같은 경우 equals메서드의 규약을 따른다고 되어있지만
Comparable 클래스의 compareTo는 equals와 달리 다른 객체를 신경스지 않아도 된다. 타입이 다른 객체가 주어지면 ClassCastException을 발생시키면 된다. 하지만 다른 타입의 비교도 허용하고 싶다면 공통 인터페이스를 통해 구현할 수 있다. 하지만 정렬된 컬렉션들은 동치성을 비교할때 equals대신 compareTo를 사용하기 때문이다.
기존의 compareTo 메서드에서는 관계연산자 < 와 > 를 사용하였지만 지금은 추천하지 않는 문법입니다. 지금은 기본 박싱 클래스에 compareTo메서드에 정적 메서드로 추가되었기 때문에
BoxingClass.compare(p1, p2)처럼 사용하면 됩니다.
Integer va = Integer.valueOf(5);
Integer vb = Integer.valueOf(5);
System.out.println(Integer.compare(va , vb));
정리해보면 다음과 같다.
1. 순서를 고려해야 하는 값클래스를 작성해야 한다면 꼭 Comparable Interface를 구현하여 쉽게 정렬하고 검색하고 비교할 수 있도록 한다.
2. compareTo메서드에서 값을 비교할때는 < 와 > 를 사용하지 않고 박싱된 기본 타입 클래스가 제공하는 정적메서드나 Comparator Interface가 제공하는 비교자 생성 메서드를 사용하라.