comparable 은 인터페이스며
지금까지 정렬을 위해 사용한다고 생각했다.
반쪽짜리 정답을 외운 채
알고리즘 프로그래밍 문제를 풀이하다 벽에 부딪혔다.
comparable 은
객체끼리 비교 할 수 있도록 한다.
정확히는
주체가되는 것은 자기자신객체며 매개변수로 들어오는 객체와의 비교를 한다.
이해를 위해
조금은 조잡한 예제를 만들어봤다.
public class ComparableDemo {
static class Car {
String name;
int hp; //최대 마력
Car () {}
Car (String name, int hp) {
this.hp = hp;
this.name = name;
}
}
이러한 클래스로 객체 5개 를 생성하고 List에 추가하여 최대마력을 가지고 오름차순으로 정렬하려고한다.
List<Car> carList = new ArrayList<>();
carList.add(new Car("car1",800));
carList.add(new Car("car2",500));
carList.add(new Car("car3",200));
carList.add(new Car("car4",150));
carList.add(new Car("car5",400));
현재는list에 추가 된 데이터 순서로 정렬 돼있을것이다.
이것을 원하는 모양으로 정렬하기위해서 어떻게 해야할까?
먼저 데이터가 Integer형식이라면 sort 함수를 활용하여 쉽게 정렬할 수 있다.
int a = 1;
int b = 2;
이같은 경우라면 a < b 라는 것은 java가 알 수 있다는 말이다.
하지만 지금 리스트에 추가된 데이터형식은
내가 만든 Car클래스형식이다
때문에 리스트에 추가된 객체는 사용자가 지정해주지 않는 한 대소관계를 알 수 없다.
이때 사용하는것이 comparable 이다.
interface Comparable<T> {...}
라고 되어있다.
<>사이에있는 T는 비교 할 객체 타입을 의미한다.
Car와 Car의 비교를 하고 싶었으니 <Car>로 사용 하면 되겠다.
따라서 이렇게 사용하면 된다.
class Car implements Comparable<Car> {
String name;
int hp; //최대 마력
Car () {}
Car (String name, int hp) {
this.hp = hp;
this.name = name;
}
@Override
public int compareTo(Car o) {
.
.
.
}
}
Comparable은 interface 이기때문에
compareTo라는 메서드를 완성시켜야한다.
@Override
public int compareTo(Car o) {
//자신의 hp보다 매개변수 hp가 더큰경우 음수
if (this.hp < o.hp){
return -1;
}
//자신과 매개변수의 hp가 같은경우 0
else if (this.hp == o.hp)
{
return 0;
}
//자신의 hp가 매개변수의 hp보다 큰경우 양수
else
{
return 1;
}
}
compareTo는 int를 반환하게 돼있다.
기준이 무엇일까
생각해보자 자신과 매개변수의 hp비교이다.
나자신이 매개변수 hp와의 값을 비교하여 대소관계를 파악해야한다.
나의 hp = 20이고
비교할 매개변수의 hp = 40 일때
나는 메개변수hp보다 -20만큼 작다는 뜻이다.
앞에 양수 음수 0 표현도 이때문이다.
실행이 잘 되는지 살펴보자
public static void main(String[] args) {
Car car1 = new Car("myCar", 20);
Car car2 = new Car("yourCar", 40);
if (car1.compareTo(car2) < 0){
System.out.println(car1.name + "가 " + car2.name + "보다 작습니다");
} else if (car1.compareTo(car2) == 0){
System.out.println(car1.name + "가 " + car2.name + "와 같습니다.");
} else {
System.out.println(car1.name + "가 " + car2.name + "보다 큽니다.");
}
}
(자신)car1.compareTo((매개변수)car2);
실행해본 결과 대소관계를 확인 할 수 있었다.
자신과 매개변수의 hp의 값을 가지고 비교하였고,
값 차이를 가지고 양수,음수,또는 0 을 반환한다고 하였다.
그렇다면 더 간결하게 표현할 수 있을것이다.
public class ComparableDemo
static class Car implements Comparable<Car> {
String name;
int hp; //최대 마력
Car () {}
Car (String name, int hp) {
this.hp = hp;
this.name = name;
}
@Override
public int compareTo(Car o) {
return this.hp - o.hp;
}
}
}
이렇게 하면 자신보다 매개변수가 클때 음수, 같을때 0, 작을때 양수가 반환될 것이다.
이로서 비교는 끝이났다.
이것을 가지고 오름차순을 정렬 할 수 있겠다.
public static void main(String[] args) {
List<Car> arrayList = new ArrayList<>();
arrayList.add(new Car("car1",800));
arrayList.add(new Car("car2",500));
arrayList.add(new Car("car3",200));
arrayList.add(new Car("car4",150));
arrayList.add(new Car("car5",400));
System.out.println("==정렬 전==");
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i).name + ":" + arrayList.get(i).hp + " ");
}
System.out.println();
System.out.println("==정렬 후==");
Collections.sort(arrayList);
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i).name + ":" + arrayList.get(i).hp + " ");
}
}
compareTo 메서드는
자기자신과 매개변수로 들어온 객체를 비교하는 것이기 때문에
반환값이 양수면 자기자신이 큰것이고,
음수면 매개변수가 더큰것이며,
0이면 크기가 같다는 뜻이 되겠다.
이와 반대로
public static void main(String[] args) {
Car car1 = new Car("myCar", 20);
Car car2 = new Car("yourCar", 40);
if (car1.compareTo(car2) < 0){
System.out.println(car1.name + "가 " + car2.name + "보다 작습니다");
} else if (car1.compareTo(car2) == 0){
System.out.println(car1.name + "가 " + car2.name + "와 같습니다.");
} else {
System.out.println(car1.name + "가 " + car2.name + "보다 큽니다.");
}
}
여기서
public int compareTo(Car o) {
return o.hp - this.hp;
}
이렇게 반환한다고하면
40 - 20 이 되고
자기자신hp가 더 작은값임에도
불구하고 양수가 나오기때문에
내림차순 정렬이 된다.