Java - Comparable

<이펙티브 자바>

Posted by Yan on August 25, 2021

이펙티브 자바 책을 읽으면서 새로 알게 된 부분을 기록한 것입니다.

Comparable을 구현할지 고려하라

  • compareTo = Comparable 인터페이스의 유일한 메소드
  • Object의 메소드가 아니다.
  • 단순 동치성 비교에 더해 순서까지 비교할 수 있으며, 제네릭하다.
  • Comparable을 구현했다 == 그 클래스의 인스턴스들에는 자연적인 순서가 있음을 뜻함.
  • Comparble을 구현한 객체들의 배열을 정렬하는 방법 == Arrays.sort(a)
  • 자바 플랫폼 라이브러리의 모든 값 클래스와 열거 타입이 Comparable을 구현했다.

구현 방법

1
2
3
public interface Comparable<T> {
    int compareTo(T t);
}

compareTo 메소드의 일반 규약

  • 이 객체와 주어진 객체의 순서를 비교한다.
  • 모든 객체에 대해 전역 동치관계를 부여하는 equals 메소드와 달리, compareTo는 타입이 다른 객체를 신경쓰지 않아도 된다. 타입이 다른 객체가 주어지면 ClassCastException을 던진다.
  • 비교를 활용하는 클래스의 예
    • 정렬된 컬렉션인 TreeSet과 TreeMap
    • 검색과 정렬 알고리즘을 활용하는 유틸리티 클래스
  1. 두 객체의 참조 순서를 바꿔 비교하면 음양이 바뀐 결과가 나와야한다.
    -> 첫 번째 객체가 두 번째보다 크고, 두 번째가 세 번째보다 크면 첫 번째는 반드시 세 번째보다 커야한다.
  2. 크기가 같은 객체들끼리는 어떤 객체와 비교하더라도 항상 같아야 한다.
  3. compareTo 메소드로 수행한 동치성 테스트의 결과가 equals와 같아야 한다.
  • 위 세 규약은 compareTo 메소드로 수행하는 동치성 검사도 equals 규약과 똑같이 반사성, 대칭성, 추이성을 충족해야함을 뜻함
  • 기존 클래스를 확장한 구체 클래스에서 새로운 값 컴포넌트를 추가했다면 compareTo 규약을 지킬 방법이 없다.
  • Comparable을 구현한 클래스를 확장해 값 컴포넌트를 추가하고 싶다면, 확장하는 대신 독립된 클래스를 만들고, 이 클래스에 원래 클래스의 인스턴스를 가리키는 필드를 두면 된다. 그 다음 내부 인스턴스를 반환하는 ‘뷰’ 메소드를 제공하면 된다. 이렇게 하면 바깥 클래스에 우리가 원하는 compareTo 메소드를 구현해 넣을 수 있다.

compareTo 메소드 작성 요령

  • Compareble은 타입을 인수로 받는 제네릭 인터페이스이므로, compareTo 메소드의 인수 타입은 컴파일타임에 정해진다.
  • 입력 인수의 타입을 확인하거나 형변환할 필요가 없다는 뜻
  • 인수의 타입이 잘못됐다면 컴파일 자체가 되지 않음
  • null을 인수로 넣어 호출하면 NullPointerException을 던져야 함