본문 바로가기

Language/Java

[Java]Comparable, Comparator

자바스크립트 공부 할 때도 정렬이 서툴렀다.

그래서 헷갈리지 않게 제대로 정리하려고 한다.

 

...더보기

Comparable - 원래 기준이 있는 정렬

Comparator - 원래 기준이 없어서 새로 기준을 만들어야 하는 정렬

Comparable

import java.util.Arrays;

public class sorting {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student[] School = {
				new Student("Tom",90),
				new Student("Jim",112),
				new Student("Mije",990),
				new Student("Ann",390),
		};
		Arrays.sort(School);
		System.out.println(Arrays.toString(School));
	}
}

class Student implements Comparable{
	int score;
	String name;
	
	Student(String name, int score){
		this.name = name;
		this.score = score;
	}
	
	public String getName() {
		return this.name;
	}
	
	public String toString() {
		return "["+name+","+score+"]";
	}
	
	public int compareTo(Object student) {
		Student nexStudent = (Student)student;
		System.out.println(
				"현재 학생: "+this.name+ "다음 학생: "+nexStudent.getName());
		return nexStudent.score-this.score;
	}
	
}

다음은 Student객체의 성적순으로 정렬하는 코드이다.

추상 객체 인터페이스인 Comparable을 구체화 시키고

 

Object클래스 안에 들어 있는 compareTo 메소드를 오버라이딩하면서 정렬 기준을 만든다.

이때 파라미터는 무조껀 Object로 받아서 캐스팅 해주어야 한다.

 

어떤 순서로 정렬될까 궁금해서 출력을 해봤는데 다음과 같다.

현재 학생: Jim다음 학생: Tom
현재 학생: Mije다음 학생: Jim
현재 학생: Ann다음 학생: Mije
현재 학생: Ann다음 학생: Jim
현재 학생: Ann다음 학생: Mije

아마 자바의 여러가지 정렬 기준을 따라서 여러 값이 왔다 갔다 하면서 정렬 되는 것 같다.

 

결국 양의 수 대로 정렬이 된다.

(위의 예시 경우에는

Tom(90)-Jim(112) = 음

Jim(112) - Mije(990) = 음

Mije(990) - Ann(390) = 양

Jim(112) - Ann(390) = 음

Mije(990) - Ann(390) = 양

이기 때문에 Mije Ann Jim Tom 순이고 반대로 오름차순인 경우는

Jim(112)-Tom(90)- = 양

Mije(990)-Jim(112)  = 양

Ann(390) - Mije(990)  = 음

Ann(390) - Jim(112)  = 양

Ann(390) - Mije(990) = 음

이다.)

 

만약 Comparable을 구체화하여 오버라이딩 하지 않는다면

< cast하세요. >

다음과 같은 에러를 발생시킨다.

Comparator

import java.util.Arrays;
import java.util.Comparator;

public class sorting {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student[] School = {
				new Student("Tom",90),
				new Student("Jim",112),
				new Student("Mije",990),
				new Student("Ann",390),
		};
//		Arrays.sort(School);
		Arrays.sort(School, new NameSort());
		System.out.println(Arrays.toString(School));
	}
}

class NameSort implements Comparator{
	public int compare(Object pre, Object next) {
		Student preStudent = (Student)pre;
		Student nextStudent = (Student)next;
		return preStudent.name.compareTo(nextStudent.name);
	}
}

class Student implements Comparable{
	int score;
	String name;
	
	Student(String name, int score){
		this.name = name;
		this.score = score;
	}
    ... 이하 생략

Comparable을 이용하여 compareTo로 정렬한 경우에는

sort 메소드에서 두번째 파라미터로 받을 Comparator를 생략하고

첫번째 파라미터인 오브젝트에서 Comparable인터페이스의 compareTo메소드에 따라 정렬하지만

sort 메소드에서 두번째 파라미터로 Comparator를 구체화한 클래스의 인스턴스를 입력시에는

이 클래스를 기준으로 정렬한다.

Comparator는

compare메소드를 오버라이딩해야하며

return은 compareTo()메소드를 이용하여, a.compareTo(b)와 같은 식으로 오브젝트를 비교한다.

 

이 때 compareTo는 a(이전값)이 클 때 양수를 뱉어낸다.

 

심화

만약 동점자가 있고 그에 동점일 경우에는 이름순으로 처리하고 싶을 땐 어떻게 하면 좋을까?

		Student[] School = {
				new Student("Tom",90),
				new Student("Jim",112),
				new Student("Mije",990),
				new Student("Andrew",990),
				new Student("Ann",390),
		};

다음 예제의 결과는 다음과 같다.

< Mije가 먼저 들어왔기 때문 >

	public int compareTo(Object student) {
		Student nextStudent = (Student)student;
		if(this.score-nextStudent.score>0) {
			return 1;
		}
		if(this.score-nextStudent.score<0) {
			return -1;
		}
		if(this.score-nextStudent.score == 0) {
			return this.name.compareTo(nextStudent.name);
		}
		return this.score-nextStudent.score;
	}

하지만 compareTo메소드를 다음과 같이 수정하면 성적이 동점일 경우 이름순으로 출력된다.

만약 이전값이 다음값보다 크다면 양수를 아닐 경우엔 음수를 반환하고

동점일 경우에는 compareTo메소드를 이용하면 된다.

Comparator

class NameSort implements Comparator{
	public int compare(Object pre, Object next) {
		Student preStudent = (Student)pre;
		Student nextStudent = (Student)next;
		if(preStudent.score-nextStudent.score>0) {
			return 1;
		}
		if(preStudent.score-nextStudent.score<0) {
			return -1;
		}
		if(preStudent.score-nextStudent.score == 0) {
			return preStudent.name.compareTo(nextStudent.name);
		}
		return preStudent.score-nextStudent.score;
	}
}

역시 같은 로직을 이용하면 가능하다.