[Java] Comparable, Comparator의 차이 + Overriding

김도윤·2025년 1월 6일

추가 공부

목록 보기
4/8
post-thumbnail

🎈절댓값 힙

https://www.acmicpc.net/problem/11286

백준 문제를 풀이하면서 절댓값 함수 Math.abs()를 사용해야 하는 것은 알고 있으나 어떻게 우선순위 큐에 활용을 해야할지 몰라 해설을 보았는데,
오버라이딩과 Comparator 인터페이스를 사용하는 것을 보고 정리를 해보려고 합니다.

🎈 Comparabel과 Comparator의 기능

  • 객체를 비교할 수 있도록 사용

    ex) 클래스 내의 객체를 비교할 때

    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반
    		
    		/*
    		   어떻게 비교..?
    		   
    		   if(a > b) ..?
    		 */		
    	}
    }
    
    class Student {
    
    	int age;			// 나이
    	int classNumber;	// 학급
    	
    	Student(int age, int classNumber) {
    		this.age = age;
    		this.classNumber = classNumber;
    	}
    }
    • 두 객체 a 학생과 b 학생이 있을 때 무엇을 기준으로 비교할지 판단이 불가능하다.
      따라서, 이러한 문제점 해결을 위해 Comparable 또는 Comparator을 사용한다
    • 이 두 인터페이스에도 차이가 존재한다
      • Comparable은 자기 자신과 매개변수 객체를 비교
      • Comparator는 두 매개변수 객체를 비교
      • Comparabledms lang 패키지에 속해있어 import를 해줄 필요가 없으나, Comparator는 util 패키지에 있어 선언을 해주어야 한다.

✏️ Comparable

  • ex) ClassName을 비교하고 싶을 때
    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;
    		}
    	}
    }

    • Student 클래스에 Comparable을 implements한다
    • Comparable<> 사이에 들어갈 타입은 Student 객체와 또 다른 Student 객체를 비교해야 하므로 <> 타입 또한 Student가 되어야 한다

    • 조건문을 통해 대소비교를 하고 그에 따라 1, 0, -1을 반환하는 방식이 정석적인 방법이지만 양수, 0, 음수로 표현하여도 무관하다
    public int compareTo(Student o) {
      	return this.age - o.age;
      }

✏️ Comparator

  • ex) classNumber을 비교하고 싶을 때
    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;
    		}
    	}
    }
    • Comparable의 compareTO()와는 다르게 자기 자신이 아닌 다른 두 객체를 비교하는 것을 확인할 수 있다
    • import java.util.Comparator; 선언해야 한다
    • compare 함수도 위와 마찬가지로 간략하게 할 수 있다
      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객체보다 작습니다.");
    		}		
    	}
    }
    
    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;
    	}
    }
    • Compaartor을 구현하는 두 번째 방법(추천)
      	
      	// 학급 대소 비교 익명 객체
      	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;
      	}
      	
      }
      • 익명객체를 이용한 방법으로 외부에서 Comparator을 구현하였기 때문에, Student 클래스 내부에서 구현해줄 필요가 없어짐

🎈 Comparable, Comparator 정렬 관계

  • Java에서의 정렬은 특별한 정의가 되어있지 않는 한 오름차순을 기준
  • 즉 선행 원소가 후행 원소보다 작다는 뜻이기에 compare 혹은 compareTo를 사용하여 객체를 비교할 경우
    • 음수가 나오면 두 원소의 위치를 바꾸지 않는다
    • 양수가 나오면 두 원소의 위치를 교환 한다
    • 같으면 두 원소의 위치는 그대로

      ex)

      import java.util.Arrays;
      import java.util.Comparator;
      
      public class Test {
      	
      	public static void main(String[] args) {
      		
      		MyInteger[] arr = new MyInteger[10];
      		
      		// 객체 배열 초기화 (랜덤 값으로) 
      		for(int i = 0; i < 10; i++) {
      			arr[i] = new MyInteger((int)(Math.random() * 100));
      		}
      
      		// 정렬 이전
      		System.out.print("정렬 전 : ");
      		for(int i = 0; i < 10; i++) {
      			System.out.print(arr[i].value + " ");
      		}
      		System.out.println();
      		
      		Arrays.sort(arr, comp);		// MyInteger에 대한 Comparator을 구현한 익명객체를 넘겨줌
             
      		// 정렬 이후
      		System.out.print("정렬 후 : ");
      		for(int i = 0; i < 10; i++) {
      			System.out.print(arr[i].value + " ");
      		}
      		System.out.println();
      	}
      	
      	static Comparator<MyInteger> comp = new Comparator<MyInteger>() {
      		
      		@Override
      		public int compare(MyInteger o1, MyInteger o2) {
      			return o1.value - o2.value;
      		}
      	};
      }
      
      class MyInteger {
      	int value;
      	
      	public MyInteger(int value) {
      		this.value = value;
      	}	
      	
      }

profile
나태해 지지 말고 꾸준히

0개의 댓글