객체를 비교할 수 있도록 만들어줍니다.
기본 자료형(primitive types)은 자바에서 내장된 부등호(>, <)로 비교가 가능합니다.
하지만, 사용자가 정의한 클래스의 객체를 비교하려면 명확한 기준을 지정해야 합니다.
예를 들어, 학생 객체 두 개를 비교할 때, 성적, 나이, 이름 등 다양한 기준을 정할 수 있습니다.
특정 기준에 따른 객체간의 비교를 위해 Comparable 또는 Comparator 인터페이스를 사용합니다.
이 둘은 모두 인터페이스입니다.
Comparable 와 Comparator를 사용해주려면 인터페이스 내에 선언된 메소드를 반드시 오버라이딩해줘야 합니다.
Comparable 인터페이스는 compareTo(T o) 메소드를 오버라이딩
Comparator 인터페이스는 compare(T o1, T o2) 메소드를 오버라이딩
Comparable 인터페이스는 기본적으로 '자기 자신'과 비교하는 메소드인 compareTo를 오버라이딩하여 사용합니다.
Comparator 인터페이스는 '두 객체'를 비교하는 메소드인 compare를 오버라이딩하여 사용합니다.
클래스에 Comparable 인터페이스를 implements하여 사용하며, compareTo() 메소드를 오버라이딩하여 비교 기준을 정의합니다.
class ClassName implements Comparable<ClassName> {
@Override
public int compareTo(ClassName o) {
// 비교 로직
}
}
compareTo() 메소드는 자기 자신과 매개변수 객체의 특정 속성을 비교하여, 그 차이에 따라 양수, 0, 음수로 값을 반환하는데, 각각의 경우를 1, 0, -1로 표현하는게 일반적입니다.
이 코드는 두 객체의 나이를 비교하여, 나이가 많으면 양수(1), 같으면 0, 적으면 음수(-1)를 반환합니다.
class Student implements Comparable<Student> {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
@Override
public int compareTo(Student o) {
// 자기자신의 age가 o의 age보다 크다면 양수
if(this.age > o.age) {
return 1;
}
// 자기 자신의 age와 o의 age가 같다면 0
else if(this.age == o.age) {
return 0;
}
// 자기 자신의 age가 o의 age보다 작다면 음수
else {
return -1;
}
}
}
위의 방법을 더 간편하게 바꾸어 두 값의 차이를 return 해주어도 되므로, 아래의 코드처럼 두 값의 차를 return해도 결과는 똑같습니다.
(단, 빼는 과정에서 Overflow가 발생할수도 있으므로, 범위에 주의해야됨)
class Student implements Comparable<Student> {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
Comparator는 별도의 비교 로직을 외부에서 정의할 수 있기 때문에, 하나의 클래스에 여러 기준으로 정렬을 적용할 수 있습니다.
import java.util.Comparator;
class ClassName implements Comparator<ClassName> {
@Override
public int compare(ClassName o1, ClassName o2) {
// 비교 로직
}
}
compare() 메소드는 두 객체 간의 특정 속성을 비교하고, 차이에 따라 양수, 0, 음수를 반환합니다.
아래의 코드는 두 객체의 나이를 비교하여, 나이가 많으면 양수(1), 같으면 0, 적으면 음수(-1)를 반환합니다.
import java.util.Comparator; // import 필요
class Student implements Comparator<Student> {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
@Override
public int compare(Student o1, Student o2) {
// o1의 학급이 o2의 학급보다 크다면 양수
if(o1.classNumber > o2.classNumber) {
return 1;
}
// o1의 학급이 o2의 학급과 같다면 0
else if(o1.classNumber == o2.classNumber) {
return 0;
}
// o1의 학급이 o2의 학급보다 작다면 음수
else {
return -1;
}
}
}
위의 방법을 더 간편하게 바꾸어 두 값의 차이를 return 해주어도 되므로, 아래의 코드처럼 두 값의 차를 return해도 결과는 똑같습니다.
(마찬가지로, 빼는 과정에서 Overflow가 발생할수도 있으므로, 범위에 주의해야됨)
import java.util.Comparator; // import 필요
class Student implements Comparator<Student> {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
@Override
public int compare(Student o1, Student o2) {
/*
* 만약 o1의 classNumber가 o2의 classNumber보다 크다면 양수가 반환 될 것이고,
* 같다면 0을, 작다면 음수를 반환할 것이다.
*/
return o1.classNumber - o2.classNumber;
}
}
Comparator를 구현하는 익명객체를 생성하여 이용하려는 클래스 내부에서 구현해주지 않고도 사용해줄 수 있습니다.
익명 객체는 main() 메서드 안에서 non-static으로 생성해도 되고, 필요에 따라 static으로 선언해 사용할 수도 있습니다.
익명 객체는 필요에 따라 여러 개를 생성할 수 있고 변수명만 달리하면 다양한 비교 기준을 정의할 수 있습니다.
아래의 코드는 학급, 나이를 썼는데 성적 등등 원하는대로 더 추가할 수 있습니다.
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
Student a = new Student(17, 2); // 17살 2반
Student b = new Student(18, 1); // 18살 1반
Student c = new Student(15, 3); // 15살 3반
// 학급 기준 익명객체를 통해 b와 c객체를 비교한다.
int classBig = comp.compare(b, c);
if(classBig > 0) {
System.out.println("b객체가 c객체보다 큽니다.");
}
else if(classBig == 0) {
System.out.println("두 객체의 크기가 같습니다.");
}
else {
System.out.println("b객체가 c객체보다 작습니다.");
}
// 나이 기준 익명객체를 통해 b와 c객체를 비교한다.
int ageBig = comp2.compare(b, c);
if(ageBig > 0) {
System.out.println("b객체가 c객체보다 큽니다.");
}
else if(ageBig == 0) {
System.out.println("두 객체의 크기가 같습니다.");
}
else {
System.out.println("b객체가 c객체보다 작습니다.");
}
}
// 학급 대소 비교 익명 객체
public static Comparator<Student> comp = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.classNumber - o2.classNumber;
}
};
// 나이 대소 비교 익명 객체
public static Comparator<Student> comp2 = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
};
}
class Student {
int age; // 나이
int classNumber; // 학급
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
}
자바에서 배열이나 리스트를 정렬할 때, Arrays.sort()와 Collections.sort() 메소드를 사용하게 되는데, 숫자나 문자열 등 primitive type에서만 동작하고, 오름차순으로 정렬됩니다.
이를 확장시켜, Arrays.sort()와 Collections.sort() 메소드를 이용하여 객체배열이나 리스트를 Comparator와 Comparable 인터페이스를 통해 비교 기준을 정의하여 정렬할 수 있습니다.
public int compare(MyClass o1, MyClass o2) {
return o1.value - o2.value; // 오름차순: 작은 값이 앞에 오도록
}
public int compare(MyClass o1, MyClass o2) {
return o2.value - o1.value; // 내림차순: 큰 값이 앞에 오도록
}
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(17, 2)); // 17살 2반
students.add(new Student(18, 1)); // 18살 1반
students.add(new Student(15, 3)); // 15살 3반
// 익명 객체를 사용한 Comparator 구현
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age; // 나이 기준 정렬
}
});
// 정렬 결과 출력
for (Student s : students) {
System.out.println("나이: " + s.age + ", 학급: " + s.classNumber);
}
}
}
class Student {
int age;
int classNumber;
Student(int age, int classNumber) {
this.age = age;
this.classNumber = classNumber;
}
}
import java.util.*;
class Student {
int age;
int score;
Student(int age, int score) {
this.age = age;
this.score = score;
}
}
public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(20, 85));
students.add(new Student(18, 90));
students.add(new Student(22, 70));
// 성적 기준으로 정렬
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.score - o1.score; // 성적 내림차순 정렬
}
});
for (Student s : students) {
System.out.println("Age: " + s.age + ", Score: " + s.score);
}
}
}