Comparable/Comparator interface

YongJun·2023년 9월 16일

JAVA

목록 보기
21/24
post-thumbnail

Comparable/Comparator interface??

  • 객체를 정렬하는데 필요한 메소드가 정의되어 있다 => 객체를 비교할 수 있도록 만든다.
  • 비교대상자가 더 크면(<) -1, 같다면(==) 0, 작으면(>) 1을 반환시켜줍니다.

Comparable vs Comparator

Comparable interface

  • 자기 자신과 매개변수 객체를 비교(자기 자신과 파라미터로 들어오는 객체를 비교)
  • 메소드 : compareTo(T o)
  • lang패키지에 있기 때문에 import 를 해줄 필요가 없다.

예제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) {
		return this.age - o.age;
	}
}
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반
		
		
		int isBig = a.compareTo(b);	// a자기자신과 b객체를 비교한다.
		
		if(isBig > 0) {
			System.out.println("a객체가 b객체보다 큽니다.");
		}
		else if(isBig == 0) {
			System.out.println("두 객체의 크기가 같습니다.");
		}
		else {
			System.out.println("a객체가 b객체보다 작습니다.");
		}
		
	}
 
}
//a객체가 b객체보다 작습니다.

Comparator interface

  • 두 매개변수 객체를 비교(자기 자신의 상태가 어떻던 상관없이 파라미터로 들어오는 두 객체를 비교)
  • 메소드 : compare(T o1, T o2)
  • util패키지에 있어서 import 를 해줘야 한다.

예제2

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) {
		return o1.classNumber - o2.classNumber;
	}
}
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반
			
		// a객체와는 상관 없이 b와 c객체를 비교한다.
		int isBig = a.compare(b, c);
		
		if(isBig > 0) {
			System.out.println("b객체가 c객체보다 큽니다.");
		}
		else if(isBig == 0) {
			System.out.println("두 객체의 크기가 같습니다.");
		}
		else {
			System.out.println("b객체가 c객체보다 작습니다.");
		}
		
	}
}
//b객체가 c객체보다 작습니다.

예제3

package jun;

public class PersonDTO implements Comparable<PersonDTO>{
	private String name;
	private int age;
	
	public PersonDTO(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "\t" + age;
	}
	
	@Override
	public int compareTo(PersonDTO dto) {
		if(this.age < dto.age) return -1;
		else if(this.age > dto.age) return 1;
		else return 0;
	}
	
}
package jun;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;


public class PersonSort {

	public static void main(String[] args) {
		String[] ar = {"orange", "apple", "banana", "pear", "peach", "applemango"};
		
		System.out.println("정렬 전 = ");
		for(String data : ar) {
			System.out.print(data+" ");
		}
		System.out.println();
		
		Arrays.sort(ar); //Arrays 클래스의 sort 메소드 호출 : 오름차순으로 정렬
		System.out.print("정렬 후 = ");
		for(String data : ar) {
			System.out.print(data+" ");
		}
		System.out.println();
		//---------------------------------------------------------------
		//객체 정렬
		PersonDTO aa = new PersonDTO("가",25);
		PersonDTO bb = new PersonDTO("나",40);
		PersonDTO cc = new PersonDTO("다",35);
		
		ArrayList<PersonDTO> arrayList = new ArrayList<PersonDTO>();
		arrayList.add(aa);
		arrayList.add(bb);
		arrayList.add(cc);
		
		System.out.print("정렬 전 = ");
		for(PersonDTO personDTO : arrayList) {
			System.out.print(personDTO+" ");
		}
		System.out.println();
		
		Collections.sort(arrayList); //Collections 클래스의 sort 메소드 호출(오름차순)
		
		System.out.print("정렬 후 = ");
		for(PersonDTO personDTO : arrayList) {
			System.out.print(personDTO+" ");
		}
		System.out.println();
		
		System.out.println("이름으로 내림차순");
		//Comparator 인터페이스의 compare 메소드 오버라이드
		Comparator<PersonDTO> com = new Comparator<PersonDTO>() { //익명 내부 클래스로 객체 생성
			
			@Override
			public int compare(PersonDTO dto1, PersonDTO dto2) { //객체 비교(두 매개변수 객체를 비교)
            /*
	        compareTo 메서드는 Comparable 인터페이스에 정의된 메서드로, 객체를 비교하는 데 사용됩니다. 
            하지만 String 클래스는 Comparable 인터페이스를 구현(implements)한 클래스 중 하나이며, compareTo 메서드를 문자열 비교에 맞게 재정의(override)하고 있습니다.
			따라서 dto1.getName().compareTo(dto2.getName()) 코드에서 compareTo 메서드는 String 클래스의 메서드를 호출하는 것이며, 이것은 문자열을 비교하기 위한 메서드입니다.
            Comparable 인터페이스와 compareTo 메서드는 객체 비교에 사용되지만, String 클래스는 문자열 비교를 위해 compareTo 메서드를 구현하였습니다.
	        */
				return dto1.getName().compareTo(dto2.getName())*-1; //내림차순
				//return dto1.getName().compareTo(dto2.getName())*1; //오름차순
				/*
				 첫 번째 개체가 두 번째 개체보다 작은 것으로 간주되면 음의 정수가 반환됩니다. 
				 첫 번째 개체가 두 번째 개체보다 큰 것으로 간주되면 양의 정수가 반환됩니다. 
				 개체가 동일한 것으로 간주되면 메서드는 0을 반환합니다.
				 */
				//return dto2.getName().compareTo(dto1.getName()); //내림차순
				//return dto1.getName().compareTo(dto2.getName()); //오름차순
				
			}
		};
		
		Collections.sort(arrayList, com);
		//sort(List<T> list, Comparator<? super T> c)
		
		System.out.println("정렬 후");
		for(PersonDTO personDTO : arrayList) {
			System.out.println(personDTO+" ");
		}
		System.out.println();
	}

}
/*
정렬 전 = orange apple banana pear peach applemango 
정렬 후 = apple applemango banana orange peach pear 
정렬 전 = 가	25 나	40 다	35 
정렬 후 = 가	25 다	35 나	40 
이름으로 내림차순
정렬 후
다	35 
나	40 
가	25 
*/

참고(https://st-lab.tistory.com/243)

대부분의 언어도 마찬가지지만, Java에서의 정렬은 특별한 정의가 되어있지 않는 한 '오름차순'을 기준으로 한다.
우리가 흔히 쓰는 Arrays.sort(), Collections.sort() 모두 오름차순을 기준으로 정렬이 된다는 것이다.

오름차순으로 정렬이 된다는 것은 무엇일까?
예로들어 {1, 3, 2} 배열이 있다고 가정해보자. 그럼 우리가 최종적으로 얻어야 할 배열 {1, 2, 3} 을 얻기 위해 정렬 알고리즘을 사용하게 될 것이다. 이 때, 정렬을 하기 위해 두 원소를 비교 하게 될 것 아닌가? 정렬 메소드에서 두 수를 비교하기 위해 index 0 원소와 index 1 원소를 비교한다고 가정해보자.
그럼 선행 원소인 1과 후행 원소인 3의 경우 대소관계는 어떻게 되는가? 1이 3보다 작다.
앞서 선행 원소와 후행 원소를 비교 할 때, 얼마큼 차이가 나는지를 반환한다고 헀다.
return o1 - o2; 를 한다면, 1-3 = -2로 '음수'가 나올 것이다.
이 때, 자바에서는 오름차순을 디폴트 기준으로 삼고 있다고 했다. 이 말은 선행 원소가 후행 원소보다 '작다'는 뜻이다.
즉, compare 혹은 compareTo를 사용하여 객체를 비교 할 경우 음수가 나오면 두 원소의 위치를 바꾸지 않는다는 것이다.
그 다음 정렬 알고리즘에 의해 index 1 원소와 index 2 원소를 비교한다고 해보자.
선행 원소인 3이 2보다 크다.
compare 혹은 compareTo를 사용하여 index 1 원소와 index 2 원소를 비교한다면 '양수'가 나올 것이다. (3-2 = 1) 이는 곧 이러면 선행 원소가 후행 원소보다 크다는 뜻이라는 것이다.
즉, compare 혹은 compareTo를 사용하여 객체를 비교 할 경우 양수가 나오면 두 원소의 위치를 바꾼다는 것이다.
그러면 {1, 2, 3} 으로 오름차순으로 정렬 될 것이다.

그럼 규칙을 일반화 할 수 있다.

[두 수의 비교 결과에 따른 작동 방식]

음수일 경우 : 두 원소의 위치를 교환 안함
양수일 경우 : 두 원소의 위치를 교환 함

이는 선행 원소가 후행 원소보다 작으면 compare 혹은 compareTo 메소드의 반환값이 음수가 나오고, 정렬 알고리즘에서는 두 원소를 비교할 때 두 원소는 오름차순 상태라는 의미이므로 두 원소가 교환되지 않는다는 것이다.

반대로 선행 원소가 후행원소보다 크면 compare 혹은 compareTo 메소드의 반환값이 양수가 나오고, 정렬 알고리즘에서는 두 원소를 비교할 때 두 원소는 내림차순 상태라는 의미이므로 두 원소가 교환된다는 것이다.

즉, 정렬 알고리즘에서는 두 원소를 compare 혹은 compareTo 를 써서 양수값이 나오냐, 음수값이 나오냐에 따라 판단을 한다는 것이다.

위 방법이 오름차순이라면 내림차순으로 정렬하고 싶은 경우 두 원소를 비교한 반환값을 반대로 해주면 되는 것 아닌가?

쉽게 말해 두 값의 차가 양수가 된다면 이를 음수로 바꿔 반환해주고, 만약 음수가 된다면 그 값을 양수로 바꾸어 반환해주면 된다는 것이다.

profile
개(발자어)린이

0개의 댓글