🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
Comparator
' 과 ' Comparable
'둘 모두 " 인터페이스 "로
" 컬렉션을 정렬하는데 필요한 메서드 정의 "
( 각자 정렬 기준 제공 )
Comparable
: 기본 정렬 기준 구현 시 사용
▶ 사용할 객체의 클래스 내부에 Override
Comparator
: 기본 정렬 기준 외 다른 기준의 정렬 구현 시 사용
▶ 별도의 정렬 기준을 만들 때 Override
Comparable
을 구현하고 있는 클래스들은
" 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들 " 이고
( wrapper 클래스 / String / Date / File 등 )
모두 기본적으로 " 오름차순 정렬 "이 되도록 Comparable
이 구현되어 있다.
그렇기 때문에 Comparable
인터페이스가 구현된 클래스라면
" 정렬이 가능하다 "라는 것을 의미한다.
그렇다면 Comparator
는 무엇이냐..
우선 두 인터페이스의 소스를 살펴보자.
/* Comparator - java.util 패키지*/
public interface Comparator{
int compare(Object o1, Object o2) ; // 두 객체를 비교
boolean equals(Object obj) ;
// Comparator를 구현하는 클래스는 오버라이딩이 필요할 수도 있음 !!
}
/* Comparable - java.lang 패키지 */
public interface Comparable {
int comparTo(Object o) ; // 객체 자신( this )과 o 를 비교
}
사실 궁극적인 기능에 있어서는 크게 다르지 않다.
물론 선언형태나 이름, 매개변수는 다르지만
" 두 객체를 비교하는 것 "은 동일하다.
또 두 객체의 반환값은
위와 같이 compare()
와 compareTo()
둘 다 동일하다.
import java.util.* ;
class Sorting {
public static void main(String[] args) {
String[] strArr = {"Abc", "acb", "Bbc", "cba" } ;
// String은 이미 Comparable 구현으로 되있다는 점 참고
Arrays.sort( strArr ) ;
System.out.println("strArr = " + Arrays.toString(strArr)) ;
// strArr = [Abc, Bbc, acb, cba]
Arrays.sort( strArr, String.CASE_INSENSITIVE_ORDER ) ; // Ignore Case 기능
System.out.println("strArr = " + Arrays.toString(strArr)) ;
// strArr = [Abc, acb, Bbc, cba]
Arrays.sort( strArr, new Descending() ) ; // 역순 정렬 클래스
System.out.println("strArr = " + Arrays.toString(strArr)) ;
// strArr = [cba, acb, Bbc, Abc]
}
}
class Descending implements Comparator { // Comparator 인터페이스 구현
public int compare(Object o1, Object o2) {
if( o1 instanceof Comparable && o2 instanceof Comparable ) { // 형변환 가능한지 _ null일 경우는 false
Comparable c1 = (Comparable)o1 ;
Comparable c2 = (Comparable)o2 ;
return c1.compareTo(c2) * -1 // 차이 비교값을 음수로 바꿔 역순으로 변경
}
return -1 ;
}
}
여기서 Arrays.sort()
는 말 그대로 정렬하는 Arrays의 메서드인데
Comparator를 지정해주지 않으면
" 저장하는 객체 (Comparable 구현 클래스 인스턴스) 에 구현된 내용 " 에 따라 정렬된다.
static void sort(Object[] a) // 지정 Comparator X -> 객체가 구현한 Comparable에 의한 정렬
static void sort(Object[] a, Comparator c) // 지정 Comparator에 의한 정렬
위 예제의 경우
String 객체 배열로
String의 Comparable 구현은 사전순 정렬로 구현되어 있기 때문에
「 공백 - 숫자 - 대문자 - 소문자 」 순( 유니코드 ) 으로 정렬된다.
또한
대소문자를 구분하지 않고 비교하는 상수 Comparator도 제공한다.
public static final Comparator CASE_INSENSITIVE_ORDER
Integer
" 의 Comparable
위에서는 String의 경우에 대해 알아보았는데
String 뿐만 아니라
앞서 두 인터페이스는 wrapper클래스들 에서도 정의가 되어있다는 것을 알 수 있었다.
/* Integer */
public final class Integer extends Number implements Comparable {
...
public int compareTo(Object o) {
return compareTo((Integer)o) ;
}
public int compareTo(Integer anotherInteger) {
int thisVal = this.value ;
int anotherVal = anotherInteger.value ;
//비교값이 크면 -1, 같으면 0, 작으면 1 반환
return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1)) ;
// this가 작을 때 -1 / this가 같을 때 0 / this가 클 때 1
}
...
}
Integer
의 " 기본 정렬 기준 "이라고 할 수 있는 comparTo()
메서드는
위와같이 정의되어 있고
return문에서 볼 수 있듯 매개변수로 들어온 값과 비교해서 -1 / 0 / 1 중 하나의 값을 반환하면서
대소관계를 나타낸다.
이 점을 활용해 오름차순 정렬 방식을 구현할 수 있는 것이다.
( String의 문자간 compareTo()
의 경우는 유니코드의 차이가 반환되어 Integer와 다른 점 주의!! )
-1 과 0, 1로만 반환하는 것이 아닌
String처럼 차이값을 반환하도록 하고 싶다면
다시 comparTo()
를 구현해도 된다.
// Arrays.sort()를 사용할 때, compareTo()를 호출하니
// compareTo를 아래와 같이 작성하면 두 값의 차이를 반환하게 바꿀 수 있다.
public int compareTo(Integer anotherInteger) {
int thisVal = this.value ;
int anotherVal = anotherInteger.value ;
return thisVal - anotherVal ;
//내림차순의 기준으로 사용한다면 반대로 anotherVal-thisVal로 작성하면 됨.
}
기본적으로 Comparable
을 구현한 클래스들은
오름차순 기준으로 정렬된다.
Integer 또한 그렇다.
내부 정렬 기준 (compareTo()
)을 가지고 있어서 자연스럽게 오름차순으로 정렬이 되는데
Comparator
를 통해
" 내림차순을 구현하고 싶을 때 "는
String때 알아봤던 것처럼
추가적으로 Comparator
를 구현해서 " `sort()에 새로운 내림차순 정렬기준으로 제공하면 된다. "
import java.util.* ;
class Sorting {
public static void main(String[] args) {
Iteger[] arr = {10, 50, 30, 40, 20 } ;
Arrays.sort( arr ) ;
System.out.println("arr = " + Arrays.toString(arr)) ;
// arr = [10, 20, 30, 40, 50]
// sort(Object[] objArr, Comparator c) 형식으로 역순 정렬
Arrays.sort( arr, new Descending() ) ; // 역순 정렬 클래스
System.out.println("arr = " + Arrays.toString(arr)) ;
// arr = [50, 40, 30, 20, 10]
}
}
class Descending implements Comparator { // Comparator 인터페이스 구현
public int compare(Object o1, Object o2) {
if( !(o1 instanceof Integer && o2 instanceof Integer ))
// Integer가 아니면 -1 반환
return -1 ;
Integer i1 = (Integer)o1 ;
Integer i2 = (Integer)o2 ;
/*
i2 - i1 나
i2.compareTo(i1) 의 방법으로 해도 가능
*/
return i1.compareTo(i2) * -1 // 차이 비교값을 음수로 바꿔 역순으로 변경
}
}