객체 크기를 비교해 정렬하기 - Comparable과 Comparator 인터페이스
- Primitive Type(기본형 데이터 타입) : 더 이상 쪼개질 수 없는 원자성의 데이터이므로 그 자체로 크고 작음을 비교할 수 있음
- Reference Type(참조형 데이터 타입) : 대상을 나타내는 복합체로 크고 작음을 비교하기 어려움
따라서 객체를 비교 가능한 타입으로 만들어줘야 함!
Comparable 인터페이스
- 객체를 비교 가능한 타입으로 만들기 위해
Comparable<T>
인터페이스 타입으로 형변환 (implements Comparable<T>
) - Comparable 인터페이스의
compareTo(T o)
메서드를 오버라이드하여 객체에 맞게 구현한 뒤 이 메서드를 호출하여 정렬
compareTo()
- compareTo 메서드를 통해 sort 진행 시 기본적으로 오름차순 정렬됨
- compareTo는 객체 자기 자신과 매개변수로 오는 객체의 크기를 비교하므로 매개변수는 자신과 같은 타입의 매개변수 하나만 올 수 있음
-
리턴타입은 int 타입
- 음수 : 내가 매개변수 객체보다 크기 작음(원소 자리 교환 X)
- 0 : 나와 매개변수 객체 크기 같음(원소 자리 교환 X)
- 양수 : 내가 매개변수 객체보다 크기 큼(원소 자리 교환 O)
Java
public class Student implements Comparable<Student> {
int no, score;
public Student(int no, int score) {
super();
this.no = no;
this.score = score;
}
// 크기 비교 방법 1
@Override
public int compareTo(Student o) {
if (this.no == o.no) return 0;
return this.no < o.no ? -1 : 1; // 오름차순 : <, 내림차순 : >
}
// 크기 비교 방법 2
@Override
public int compareTo(Student o) {
return this.no - o.no; // 음수와 양수가 섞여있는 상황에서는 언더플로 혹은 오버플로 발생 가능(int형으로 표현하는 범위 초과)
return Integer.compare(o.no, this.no); // 언더, 오버플로 방지, 첫번째 매개변수 기준
}
}
public class ComparableTest {
public static void main(String[] args){
Student[] students = {
new Student(10, 100),
new Student(3, 50),
new Student(54, 80),
new Student(23, 10)
}
}
}
// Comparable 인터페이스의 compareTo 메서드 재정의했으므로 에러 발생 X
Arrays.sort(students);
Comparator 인터페이스
- 사용자 정의 클래스(데이터 타입)의 경우 Comparable 인터페이스의 compareTo 메서드를 적절하게 재정의하여 입맛에 맞게 정렬할 수 있지만, String 타입과 같은 API로 제공되는 참조형 데이터 타입은 재정의 불가능함
- 또한 상황에 맞게 정렬하고 싶을때마다 클래스의 메서드를 수정하는 것은 비현실적임
- 객체를 사용하는 상황에서 조금 더 간편하고 일시적인 방법으로 객체의 크기를 비교하고 정렬하기 위해
Comparator<T>
인터페이스를 구현하여 사용 - Comparator 인터페이스의
compare(T o1, T o2)
메서드는 내장 클래스로 구현하거나 익명함수, 람다식으로 구현 가능
compare()
- Comparable 인터페이스의 compareTo 메서드는 자기자신이 스스로와 다른 객체를 비교했다면, Comparator 인터페이스의 compare 메서드는 제 3자에게 비교를 요청하여 결과를 얻음
- compare 메서드를 통해 sort 진행 시 기본적으로 오름차순 정렬됨
- compare는 제 3자가 두 개의 객체의 크기를 비교하므로 매개변수로는 같은 타입의 매개변수 2개가 와야 함
-
리턴타입은 int 타입
- 음수 : 앞의 객체가 뒤의 객체보다 크기 작음(원소 자리 교환 X)
- 0 : 앞의 객체와 뒤의 객체 크기 같음(원소 자리 교환 X)
- 양수 : 앞의 객체가 뒤의 객체보다 크기 큼(원소 자리 교환 O)
Java
public class ComparatorTest {
// 내장 클래스로 구현
static class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.score - o2.score; // 점수 기준 오름차순
}
}
public static void main(String[] args) {
Student[] students = {
new Student(1, 10),
new Student(3, 50),
new Student(2, 80),
new Student(4, 10)
};
// 내장 클래스 사용
Arrays.sort(students, new StudentComparator());
// Student가 갖고있는 비교 기능(compareTo)이 적용되지 않고, 별도로 정의한 Comparator가 비교를 하고있음. 클래스에 정의한 compare와 다른 기준으로 정렬하고 싶을 때 커스텀하는 용도로 쓸 수 있음
// 익명 클래스로 구현
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.score - o1.score;
}
});
// 람다식으로 구현
Arrays.sort(students, (o1, o2) -> o2.score - o1.score);
// 기준 2개 비교
Arrays.sort(students, (o1, o2) -> o2.score != o1.score ? o2.score - o1.score : o2.no - o1.no);
int[][] students2 = {
{1, 10},
{3, 50},
{2, 80},
{4, 10}
};
// 2차원 배열 정렬
Arrays.sort(students2, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
// 2차원 배열 람다식 정렬
Arrays.sort(students2, (o1, o2) -> o1[0] - o2[0]);
}
}