본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Design Pattern/Java] Comparable 인터페이스의 구현을 고려하자.

by 돼지왕 왕돼지 2012. 3. 13.
반응형


안녕하세요 돼지왕 왕돼지입니다.

오늘은 "Comparable 인터페이스의 구현을 고려하자." 라는 주제로 이야기하고자 합니다.

이 글은 "Effective Java" 를 정리한 내용입니다.


- compareTo 메소드는 Object 클래스에 정의되어 있지 않으며, 대신에 Comparable 인터페이스에 유일하게 존재하는 메소드이다. Object 의 equals 메소드와 유사한 특성을 갖는다. 차이점이라면, 두 객체가 동일한지를 비교하는 것과 더불어 순서까지 비교할 수 있으며, 제네릭 타입을 지원한다.



Comparable 에 대해 조금만 더 설명해봐.

- 자바 라이브러리의 모든 값 클래스들은 Comparable 인터페이스를 구현했데.

- 알파벳 순, 숫자 순, 날짜 순과 같은 자연율을 갖는 값 클래스들은 반드시 Comparable 인터페이스를 구현해야 해.

- 정의는 이렇지.

public interface Comparable<T>{

   int compareTo( T t );

}


- CompareTo 메소드의 보편적 계약 내역은 equals 와 유사해. 하지만 "순서 판단"이 들어가 있지. 
  ( 어떤 필드를 먼저 비교하냐에 따라서 결과값이 달라지겠지.. )

- CompareTo 의 결과는.. 
  현재객체가 비교대상보다 작으면 음의 정수값, 같으면 0, 현재객체가 더 크면 양의 정수 값을 return 하지.

- 만일 비교대상이 비교할 수 없는 type 이면 ClassCastException 이 발생하고..



그럼 equals 와 비슷하다는 compareTo 의 조항들은 뭔데?

1. 모든 x, y 에 대하여 sgn( x.compareTo( y ) ) == - sgn ( y.compareTo( x ) ). ( Symmetric )

2. ( x.compareTo( y ) > 0 && y.compareTo( z ) > 0 ) 이면 x.compareTo( z ) > 0 . ( Transitive )

3. x.compareTo( y ) == 0 이면 모든 z에 대해 sgn ( x.compareTo( z ) == sgn ( y.compareTo( z ) ) 가 되어야 한다.

4. 반드시는 아니지만 x.compareTo( y ) == 0 이면 x.equals( y ) 이다..
  ( 이를 지키지 않는 class 에서는 API 문서에 
   "주의 : equals 메소드와 다르게 자연율 순서를 지원한다" 라고 명시해주는 게 좋다. )






자연율 순서라.. 그걸 어떻게 비교하지?

- compareTo 계약 조항을 따르는 클래스에는 저장 객체를 정렬 상태로 유지하는 컬렉션인 TreeSet 과 TreeMap 이 포함되며, 검색과 정렬 알고리즘을 갖고 있는 Collections 와 Arrays 유틸리티 클래스도 포함되어 있어. 이걸 활용해서 하는 거지.

- 참고로 알아두어야 할 것은 다른 컬렉션 인터페이스들과 다르게, TreeSet 과 TreeMap 은 저장 객체를 정렬상태로 유지하는데 equals 대신 compareTo 를 이용해서 동일 여부 검사를 한다는 거야.
예를 들어 new BigDecimal( "1.0" ) 과 new BigDecimal( "1.00" ) 은 HashSet 에서는 다른 객체로 인정되어 둘 다 저장하지만, TreeSet 에서는 하나의 BigDecimal 객체만 저장하지.





equals 와 compareTo 의 차이점이 더 있어?

- compareTo 메소드의 인자로 전달되는 비교 객체의 타입은 컴파일 시점에서 미리 결정이 돼서 메소드 내부에서 객체의 타입을 확인하거나 타입 변환을 할 필요가 없지.

- Float 과 Double 의 비교는 Double.compare 나 Float.compare 로 비교를 하고.




예제 compareTo 코드

public int compareTo( PhoneNumber pn ){
   // 뺄샘을 이용하는 방법 areacode - pn.areaCode 도 있으나,
   // overflow 와 음수 여부 등을 고려해야 하는 주의사항이 추가된다.
   if ( areaCode < pn.areaCode )
      return -1;
   if ( areaCode > pn.areaCode )
      return 1;

   if ( prefix < pn.prefix )
      return -1;
   if ( prefix > pn.prefix )
      return 1;

   if ( lineNumber < pn.lineNumber )
      return -1;
   if ( lineNumber > pn.lineNumber )
      return 1;

   return 0;
}



도움이 되셨다면 손가락 꾸욱~

반응형

댓글