관리 메뉴

제뉴어리의 모든것

Comparable과 Comparator에 대하여 본문

JAVA

Comparable과 Comparator에 대하여

제뉴어리맨 2022. 7. 10. 22:11

Comparable과  Comparator이란

이 두개는 일단 Interface이다. 그리고 이름에서 느껴지듯이 뭔가 비교를 도와주는 녀석들이다.

즉, 객체들간의 비교 방법을 정의하여 주는 인터페이스이다. 

 


Comparable란?

객체를 비교하여 정렬을 할수 있게 만들기위한 추상 메서드를 가지고 있는 인터페이스이다.

그래서 만약 어떤 클래스에서 Comparable을 구현하고 있다면, 그 클래스에서 생성되는 객체들은 객체간의 정렬 기준이 구현되어 있는것이다. (예를들어, Integer와 같은 클래스들이 있다)

Comparable 인터페이스는 compareTo(Object o) 란 메소드를 구현해주면 compareTo에 정의되어 있는 코드의 기준으로 객체들을 비교하여 정렬해준다.

 

 

https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#method.summary

 

Comparable (Java Platform SE 8 )

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method. Lists (and arrays) of o

docs.oracle.com

 

Comparable의 compareTo에 대하여

Comparable 인터페이스 내부에 정의되어 있는 compareTo(T o) 메소드는 매개변수(o) 로 들어오는 객체와,

compareTo 메소드를 호출하는 자신 객체와 비교를 하는것이다.

그리고 Comparable인터페이스는 lang 패키지에 정의되어 있다.

위 두가지 점이 Comparator의 compareTo와 다른점이다.

 

Comparable의 compareTo의 사용 방법

  • 코드
package ch11.practice.subPractice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class ComparableComparatorPractice {

    public static void main(String[] args) {

        ArrayList studentList = new ArrayList();

        studentList.add(new Student(10, "제뉴어리"));
        studentList.add(new Student(2, "준"));
        studentList.add(new Student(9, "메이"));
        studentList.add(new Student(7, "마치"));
        studentList.add(new Student(8, "줄라이"));
        studentList.add(new Student(9, "어거스트"));

        Collections.sort(studentList);

        Iterator iterator = studentList.iterator();

        while (iterator.hasNext()) {
            System.out.print(iterator.next() + " ");
        }

        System.out.println();
    }
}

class Student implements Comparable<Student> {

    int grade;
    String name;

    public Student(int grade, String name) {
        this.grade = grade;
        this.name = name;
    }

    @Override
    public int compareTo(Student o) {

        int result;

        if(this.grade > o.grade)
            result = 1;
        else if(this.grade == o.grade)
            result = 0;
        else
            result = -1;

        return result;
    }

    @Override
    public String toString(){
        return String.format("[%s : %d]", name, grade);
    }
}

 

  • 결과

ArrayList에 저장되어 있는 Student가 grade(학년) 를 기준으로 정렬되어 있다.

 

Comparable의 compareTo 결과에 대한 설명

우선 위에 설명하였다시피 객체를 비교할때 기준을 정하여 주고 싶다면 해당 클래스에

Comparable 인터페이스를 구현하고 compareTo 메서드를 재정의 해주어야 한다.

그리고 Collection.sort 메서드는 매개변수인 Collection의 요소들을 기본적으로 오름차순으로 정렬하여 준다.

(당연히 그 요소 클래스는 Comparable 구현되어 있어야한다)

그리고 Comparable의 compareTo 메서드는 본객체의 grade와 매개변수 객체의 grade를 비교하여 1,0,-1 중 리턴하여 주는데, 이 의미는 1 리턴시 본 객체가 더 크고 0 리턴시 같으며, -1 리턴시 본 객체가 더 작다는 의미이다.

크다, 같다, 작다란 의미는 아래와 같다

 

7 - 4 =  3 ( 7이 2번째 피연산자보다 크다 => 결과 : 3(양수) )

4 - 7 = -3 ( 4가 2번째 피연산자보다 작다 => 결과 : -3(음수))

7 - 7 =  0 ( 7이 2번째 피연산자와 같다 => 결과 : 0 )

 

즉, 결과가 양수 3이든 1이든 음수 -3이든 -1이든 

본 객체가 큰지 작은지는 양수, 음수 만으로 충분히 표현이 가능한것이다.

그래서 해당 값을 리턴해주면 sort 메서드는 내부적으로 알아서 큰 객체임을 인지해서 뒤쪽으로 정렬을 해주는것이다.

그런데 만약 내림차순 정렬을 하고 싶다면?

결과값만 -1 을 곱해주면 되는것이다. 그럼 무조건 결과값은 반대일테니까.

 

 


Comparator란?

Comparator 또한 객체를 비교하여 정렬을 할수 있게 만들기위한 추상 메서드를 가지고 있는 인터페이스이다.

 

Comparator의 compareTo에 대하여

Comparator 인터페이스 내부에 정의되어 있는 compareTo(T o1, T o2) 메소드는 

매개변수 o1 객체와 o2 객체를 비교하여 대소결과를 리턴하여 주는 메서드이다.

그리고 Comparator인터페이스는 util 패키지에 정의되어 있다.

위 두가지 점이 Comparable의 compareTo와 다른점이다.

 

 

Comparator의 compareTo의 사용 방법

  • 코드

package ch11.practice.subPractice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

public class ComparatorPractice {
    public static void main(String[] args) {

        ArrayList catList = new ArrayList();

        catList.add(new Cat(10, "냐옹"));
        catList.add(new Cat(3, "고랭이"));
        catList.add(new Cat(4, "냐냐옹"));
        catList.add(new Cat(12, "캣츠비"));

        Comparator<Cat> comparator = new Comparator<Cat>() { //비교 방법을 정의한 익명클래스 객체 생성
            @Override
            public int compare(Cat o1, Cat o2) {

                int result;

                if(o1.age > o2.age)
                    result  = 1;
                else if(o1.age == o2.age)
                    result  = 0;
                else
                    result  = -1;

                return result;
            }
        };

        Iterator iterator1 = catList.iterator();

        System.out.println("============ 정렬 전 ============");
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }
        System.out.println("============ 정렬 전 ============");
        
        Collections.sort(catList, comparator); //정렬

        System.out.println("============ 정렬 후 ============");
        Iterator iterator2 = catList.iterator();

        while (iterator2.hasNext()) {
            System.out.println(iterator2.next());
        }

        System.out.println("============ 정렬 후 ============");
    }
}

class Cat {

    int age;
    String name;

    public Cat(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return String.format("[%s : %d]", name, age);
    }
}

 

  • 결과

Collection.sort 메서드에 

catList와 Cat 객체간의 비교 방법을 정의한 Comparator를 상속받은 익명클래스 객체를 매개변수로 넘겨주어서 정렬하였다.

 

Comparator의 compareTo 결과에 대한 설명

Cat 객체간의 비교를 정의해준 Comparator를 상속한 익명 클래스 객체 comparator를 생성하여

Collection.sort 메서드에 Cat 객체들이 들어있는 catList와 함께 매개변수로 넘겨 주었다.

그런데 Collection.sort 메서드로 정렬시 컬랙션의 각 요소객체들이 Comparable을 구현하였다면 따로 Comparator 를 재정의한 익명 클래스 객체를 매개변수로 넘겨 줄 필요가없다.

그리고 만약 Cat 클래스에서 Comparator 를 구현하여 compareTo(T o1, T o2)를 재정의 하였다고 해서

Collection.sort 에서 Comparator 구현체 객체의 인자값 없이 정렬도 되지 않는다.

Collection.sort 메서드의 오버로딩으로 인해 Collection 구현체만 넘겨주는 sort 메서드는 컬랙션의 요소객체에 무조건 Comparable이 구현되어 있어야한다.

 

결론,

Collection.sort 사용시 비교 방법을 매개변수로 넘겨주고 싶다면 Comparator를 상속받은 익명 클래스 객체를 만들어 Collection 구현체와 함께 넘겨주고 (매개변수 2개)

Collection.sort 사용시 Collection 구현체 1개만 매개변수로 보내고 싶다면

Collection의 요소 클래스에는 Comparable이 구현되어 있어야한다.

그러므로 

보통 객체의 기본 정렬방법은 Comparable로 클래스 안에 정의를 해놓고,

코드상 특수한 정렬을 원할때 Comparator 상속 익명 클래스 객체를 그때그때 생성하여 정렬하고 사용한다.

 

 

 

참조 사이트 : 

https://st-lab.tistory.com/243

 

'JAVA' 카테고리의 다른 글

익명 클래스 예제  (0) 2022.07.18
Arrays.asList() 의 대하여  (0) 2022.07.15
제네릭스(Generics)의 기본 개념 - 1  (0) 2022.07.07
배열 요소 중에 특정값이 존재하는지 검사  (0) 2022.05.15
배열 내용 출력하기  (0) 2022.05.15