1. 필요 이유
학생이라는 객체를 만들고, 해당 객체의 속성으로 나이, 성적 평균이 있다고 하자. 학생A와 학생B를 비교하고자 할 때 어떻게 비교를 해야 할까? 사용자가 기준을 정해주지 않으면 뭐로 비교를 해야 하는지 알 수가 없다. 이럴 때 Comparable 혹은 Comparator 인터페이스의 비교 메서드를 사용해야 한다.
2. Comparable
1) 개념
객체를 비교하는데 사용하는 인터페이스. 자기 자신과 매개변수로 들어오는 객체를 비교한다.
2) 메서드
compareTo(T o)
3) 구현
class Student implements Comparable<Student> {
int age;
int score;
Student(int age, int score) {
this.age = age;
this.score = score;
}
@Override
public int compareTo(Student o) {
// 내가 더 크면 양수 리턴
// 나랑 같으면 0 리턴
// 내가 더 작으면 음수 리턴
return this.age - o.age;
}
}
4) 주의
빼기를 할 때 자료형의 범위가 넘어가면 overflow나 underflow가 발생하여 원하는 결과와 다른 값이 나올 수 있으니 이를 잘 확인해야 한다.
3. Comparator
1) 개념
객체를 비교하는데 사용하는 인터페이스. 두 매개변수 객체를 비교한다.
2) 메서드
compare(T o1, T o2)
3) 구현
import java.util.Comparator; // import 필요
class Student implements Comparator<Student> {
int age;
int score;
Student(int age, int classNumber) {
this.age = age;
this.score = score;
}
@Override
public int compare(Student o1, Student o2) {
// o1이 더 크면 양수 리턴
// o1과 o2가 같으면 0 리턴
// o1이 더 작으면 음수 리턴
return o1.score - o2.score;
}
}
4) 주의
빼기를 할 때 자료형의 범위가 넘어가면 overflow나 underflow가 발생하여 원하는 결과와 다른 값이 나올 수 있으니 이를 잘 확인해야 한다.
5) 익명 클래스를 활용한 Comparator
Comparator를 사용하면 객체끼리 비교를 할 수 있다. 하지만, 이를 사용하려면 위에서처럼 새롭게 정의할 객체에 implements를 하여 해당 메서드를 구현해야 한다. 즉, 비교 기능만 따로 빼서 이를 인스턴스화해서 사용하기가 어렵게 된다.
이때, 비교 기능만 따로 빼서 사용할 수 있는 방법이 바로 익명 클래스를 활용한 Comparator이다.
ⓛ 익명 클래스
public class Anonymous {
public static void main(String[] args) {
Rectangle a = new Rectangle();
Rectangle anonymous = new Rectangle() {
int depth = 40;
@Override
int get() {
return width * height * depth;
}
};
System.out.println(a.get()); // 20
System.out.println(anonymous.get()); // 10 * 20 * 40
}
}
class Rectangle {
int width = 10;
int height = 20;
int get() {
return height;
}
}
위의 코드를 살펴보면, anonymous라는 인스턴스가 하나 있다. 이 인스턴스는 new Rectangle로 생성이 되었는데 그냥 생성이 되고 끝난 것이 아니라 생성 코드 뒤에 {}가 있고 구현이 또 되어 있다.
즉, anonymous 인스턴스는 Rectangle이라는 클래스를 상속 받았고, 본인만의 클래스 코드는 {}안에 있는데, {}안에 있는 클래스는 이름이 없다. 이런 것을 익명 클래스라고 한다.
이러한 익명 클래스는 상속할 클래스 혹은 상속할 인터페이스가 무조건 앞에 나와야 한다.
② 익명 클래스를 활용한 Comparator 구현
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
// 익명 객체 구현방법
Comparator<Student> comp1 = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.classNumber - o2.classNumber;
}
};
}
}
// 외부에서 익명 객체로 Comparator가 생성되기 때문에 클래스에서 Comparator을 구현 할 필요가 없어진다.
class Student {
int age;
int score;
Student(int age, int score) {
this.age = age;
this.score = score;
}
}
Comparable | Comparator | |
공통점 | 인터페이스이다. 인터페이스 안에는 비교할 때 사용하는 메서드가 명시되어 있다. |
|
차이점 | compareTo(T o) 메서드를 가진다 자기 자신과 매개변수를 비교한다 비교가 될 객체의 정의 부분에 implements Comparable를 작성해서 compareTo()메서드를 오버라이딩 해야 한다. |
compare(T o1, To2) 메서드를 가진다. 두 매개변수를 비교한다. 비교가 될 객체 정의에 implements Comparator를 해도 되고, 익명 클래스를 만들어 비교할 때 사용할 인스턴스를 만들어줘도 된다. |
4. Comparable, Comparator 과 정렬
1) 정렬 기본
- 정렬은 기본적으로 오름차순이다.
- 정렬을 하기 위해서는 두 원소를 비교한다. 비교를 할 때는 compare메서드를 쓰거나, compareTo 메서드를 쓴다.
- 만약 메서드의 결과가 양수라면 앞의 것이 더 크다는 것이니 두 원소의 위치를 바꾼다.
- 만약 메서드의 결과가 음수라면 뒤의 것이 더 크다는 것이 두 원소의 위치를 바꾸지 않는다.
2) 정렬 방법
Arrays.sort(정렬의 대상이 될 배열, Comparator를 상속받은 익명 클래스)
Arrays.sort(times, new Comparator<int[]>(){
@Override
public int compare(int[] S, int[] E){
if(S[1] == E[1]){
return S[0] - E[0];
}
return S[1]-E[1];
}
});
Arrays.sort(phone_book, new Comparator<String>(){
public int compare(String str1, String str2){
return str1.length() - str2.length();
}
});
만약에 Comparator에 클래스를 따로 적어주지 않으면 정렬의 대상이 될 배열 안에 있는 객체 타입에 맞는 비교 메서드가 저절로 수행된다. 예를 들어 Integer가 원소로 있다면 Integer 클래스 안에 있는 비교 메서드가 실행될 것.
*참고
https://st-lab.tistory.com/243
'자바' 카테고리의 다른 글
[자바 개념] HashMap과 TreeMap (0) | 2023.08.25 |
---|---|
[자바 개념] Date (0) | 2023.03.19 |
[자바 개념] StringTokenizer (0) | 2023.03.19 |
[자바 개념] IO(입출력) (0) | 2023.03.19 |
[자바 개념] Optional<T> (0) | 2023.03.08 |