[JAVA] 컬렉션 프레임웍 : "비교(Compare)" 정렬 인터페이스

DongGyu Jung·2022년 2월 23일
0

자바(JAVA)

목록 보기
34/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 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 를 비교
}

사실 궁극적인 기능에 있어서는 크게 다르지 않다.

물론 선언형태나 이름, 매개변수는 다르지만
" 두 객체를 비교하는 것 "은 동일하다.

또 두 객체의 반환값은

  • 같을 경우 : 0
  • 비교값보다 으면 : 음수
  • 비교값보다 면 : 양수

위와 같이 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 // 차이 비교값을 음수로 바꿔 역순으로 변경
    }    
}

0개의 댓글