SortedSet에 어떤 객체(객체가 끼리끼리 비교가능하던, 가능하지 않던 상관없이)들을

추가해야 한다면 SortedSet의 입장에서는 추가 되는 객체간 순서의 비교가 가능해야

합니다.

가장 간명한 것은 추가되는 객체 간에 Natural Ordering이 존재해서 Natural Ordering

따라 객체의 순서를 정하는 것입니다. 하지만 Natural Ordering이 근본적으로 존재하지 않는

클래스의 객체이거나, 혹은 Natural Ordering은 같은 클래스형 객체에게만 적용되는 개념

이므로, 만약 다른 클래스의 객체를 SortedSet에 추가하고자 할 때는 이 방법은 곤란합니다.

 

물론 방법이 전혀 없는 것은 아닙니다. 다만 SortedSet의 입장에서는 추가되는 객체의

순서를 정해야만 하는데, 추가되는 객체들간의 비교를 통해서 순서를 정하는 것이 아니라

SortedSet자체에 객체들을 비교 할 수 있는 일관된 기준이 있어야 합니다.

예를들어 학생들 번호를 부여할 때 학생들의 키가 기준이 되어서 작은 학생부터 1번을

부여한다던가 또는 가나다순의 학생이름이 기준이 되어서 그 순서로 번호를 부여한다던가

하는 것 말입니다.

앞에 나온 질럿 객체를 순서대로 정렬한다고 했을때는 체력이 가장 많이 남은

질럿을 앞에 세우고, 가장 적게 남은 질럿을 뒤로 보낸다 등의 기준만 있으면 질럿 객체

저희끼리 끼리는 Natural Ordering이 없어도 SortedSet에서는 추가 될 수 있습니다.

 왜냐하면 SortedSet 자체에서 객체를 비교할 수 있는 기준을 갖고 있으니까요.

추가되는 객체끼리의 Natural Ordering은 순서를 정하는데 필요하지 않습니다.

SortedSet을 만들 때 이런 비교의 기준을 지정할 수 있는데, 이 순서의 기준이 바로

Comparator 이라는 인터페이스입니다.

 

Comparator SortedSet에서 객체의 순서 기준을 나타내는 인터페이스입니다. 

때문에 인터페이스 SortedSet을 구현한 대부분의 클래스는 Comparator SortedSet

생성자에서 입력을 받습니다. (물론 Comparator역시 인터페이스이므로 Comparator객체를

입력받는게 아니라 Comparator를 구현한 객체를 SortedSet의 생성자에서 입력받습니다.)

물론 SortedSet이 생성자에서 Comparator 인터페이스를 인자로 받지 않는등

Comparator를 갖고 있지 않다면,추가되는 객체의 순서는 객체의 Natural Ordering에 의해

정해집니다.

 

 

Comparator

int compare(Object o1, Object o2)

o1 o2의 순서를 비교합니다.

boolean equals(Object obj)

obj Comparator과 같은지 알려줍니다.

  5 - 7

 

import java.util.*;

 

/**

* SortedSet의 기본 사용법을 보여줍니다.

* SortedSet에서 SortedSet Comparator를 이용합니다.

*/

public class ComparatorSortedSetDemo {

             public static void main(String[] args) {

 

                           Random random = new Random();

                           // Protoss Unit간의 비교를 할 수 있는 기준을 SortedSet에 설정합니다.

                           SortedSet s = new TreeSet(new ProtossComparator());

 

                           // Set Dragoon 10마리를 추가합니다.

                           for(int i = 0; i < 10; i++)

                                        s.add(new Dragoon(random.nextInt(100)));                   

                           // Set Reaver 10마리를 추가합니다.

                           for(int i = 0; i < 10; i++)

                                        s.add(new Reaver(random.nextInt(200)));                                               

 

                           // Set에 있는 내용을 탐색합니다.

                           for(Iterator it = s.iterator(); it.hasNext();) {

                                        // Dragoon, Reaver모두 Protoss입니다.                                   

                                        Protoss p = (Protoss)it.next();          

                                        System.out.println(p.getStrength() + "," +  p.getName());

                           }

                           System.out.println();

             }

 

}

 

/**

* SortedSet에서 순서의 기준으로 사용될 Comparator입니다.

* Protoss Unit간 비교이며, 체력이 작은 녀석이 앞섭니다.

*/

class ProtossComparator implements Comparator {

             public int compare(Object o1, Object o2) {

                           Protoss p1 = (Protoss)o1;

                           Protoss p2 = (Protoss)o2;

                          

                           if (p1.getStrength() < p2.getStrength())

                                        return -1;

                           else if (p1.getStrength() == p2.getStrength())

                                        return p1.getName().compareTo(p2.getName());

                           else

                                        return 1;

             }           

}           

 

/**

* Protoss Unit이라면 모두 가지는 메소드입니다.

*/

interface Protoss {

             public int getStrength();

             public String getName();

}

 

/**

* Protoss Unit Drogoon입니다.

*/

class Dragoon implements Protoss {

             private int strength;

             private String name;

            

             public Dragoon(int strength) {

                           this.strength = strength;

                           this.name = "드라군";

             }

             public int getStrength() {

                           return this.strength;

             }

             public String getName() {

                           return this.name;

             }

}

 

/**

* Protoss Unit Reaver입니다.

*/

class Reaver implements Protoss {

             private int strength;

             private String name;

            

             public Reaver(int strength) {

                           this.strength = strength;

                           this.name = "리버";

             }

             public int getStrength() {

                           return this.strength;

             }

             public String getName() {

                           return this.name;

             }           

}

예제 5 - 10 ComparatorSortedSetDemo.java

 

 

예제 5 - 10 ComparatorSortedSetDemo SortedSet에서 Comparator의 역할과 사용법을

잘 보여주고 있습니다.

ComparatorSortedSetDemo public static void main(String[] args) 에서는

SortedSet을 하나 만들고 있는데,대표적인 SortedSet TreeSet을 사용했습니다.

SortedSet TreeSet의 생성자에 Comparator를 인자로 주었습니다.

Comparator는 인터페이스이므로 여기서는 Comparator인터페이스를 구현한

ProtossComparator객체를 사용했습니다.

public static void main(String[] args)에 사용된 다음의 문장을 설명하면

  SortedSet set = new TreeSet(new ProtossComparator());

SortedSet을 하나 만들고, SortedSet에게 객체의 순서를 매기는 기준인 Comparator

ProtossComparator로 지정한 것입니다.

 

ProtossComparator를 살펴보면 Comparator 인터페이스를 구현한 것을 알수 있는데,

비교하는 두 개의 대상이 모두 Protoss 형 데이터인 것을 알 수 있습니다.

, TreeSet에 추가되는 객체는 모두 Protoss 데이터형인 것을 어렴풋이 알 수 있을

것입니다. Comparator ProtossComparator클래스는 체력이 작은 Protoss객체가

앞서고, 체력이 큰 Protoss가 뒤에 서는 기준을 갖고 있습니다.

그리고 같은 체력일 때는 Protoss 이름의 가나다 순으로 먼저 섭니다.

 

그리고 Protoss는 인터페이스로 설계되었습니다.

Dragoon클래스, Reaver클래스는 모두 Protoss 인터페이스를 구현했으므로 Protoss이기도

합니다. , ProtossComparator Dragoon Reaver의 순서를 설정할 수 있다는 뜻입니다.

Dragoon객체와 Reaver객체는 서로 클래스가 다르므로 Natural Ordering이 있을 수 없는데,

Comparator를 이용하면 이와 같이 순서를 정할 수 있습니다.

 

사용자 삽입 이미지

그림 5 - 8 [run ComparatorSortedSetDemo]

 

예제 5 - 10에서 SortedSet TreeSet에 추가된 것은 Dragoon객체와 Reaver객체입니다.

일반적으로는 데이터형이 다른 객체들은 SortedSet 에 추가되지 못하지만 그림 5 - 8에서

보이듯 데이터형이 다른 Dragoon Reaver가 아주 자연스럽게 추가가 되는 것은 TreeSet

이 객체의 Natural Ordering에 따라 순서를 정한 것이 아니라 스스로 만든 기준

(ProtossComparator)에 의거해서 객체를 정렬했기 때문입니다.

그 객체가 비교 가능한 객체(Comparable 객체)이던 그렇지 않은 객체 이든 전혀 상관

하지 않습니다.

서로 다른 클래스형의 객체를 SortedSet에 추가하려고 한다면 SortedSet에는 객체를

정렬할 수 있는 기준 즉, Comparator가 반드시 있어야 합니다.

 

예제 5 - 10에서는 TreeSet의 생성자에 ProtossComparator 객체를 Comparator

사용했습니다. Comparator ProtossComparator 클래스를 살펴보면 조금 재미난 구석이

있습니다.

Comparator 인터페이스에서 2개의 메소드를 선언했는데 Comparator 인터페이스를

구현한 ProtossComparator 클래스에는 2개의 메소드중 1개의 메소드만 구현했을 뿐입니다.

 

Comparator인터페이스를 구현한다고 선언한 ProtossComparator 클래스에서는

Comparator 인터페이스에서 선언한 메소드 모두를 구현하지 않은 클래스가 되었습니다.

인터페이스를 구현하는 클래스가 인터페이스에서 선언한 메소드 모두를 구현하지 않으면

asbstract 클래스, 추상클래스가 되어야 하는데,ProtossComparator 클래스는 abstract

키워드가 붙은 추상클래스로 되어야 할 것 같습니다. 그렇지 않습니까?

 

아닙니다.

자바의 모든 클래스는 java.lang.Object를 상속한 클래스이고, java.lang.Object 클래스에는

public boolean equals(Object o) 메소드가 이미 구현되어 있습니다.

Object 클래스를 상속한 ProtossComparator클래스는 자신이 정의한 것은 아니지만

java.lang.Object클래스를 상속 했기 때문에 java.lang.Object클래스에서 구현한

public boolean equals(Object o) 메소드를 갖고 있습니다.

Comparator 인터페이스에서 지정한 2개의 메소드를 모두 구현한 셈이 됩니다.

물론 ProtossComparator의 경우는 현재 순서에만 관심이 있기 때문에 public boolean

equals(Object o) 메소드를 새롭게 정의해야할 즉, 굳이 public boolean equals(Object o)

오버라이딩해야 할 이유가 없습니다.

 

ProtossComparator 클래스는 모든 객체를 비교하는 기준은 못되지만, 적어도 Protoss

인터페이스형 객체는 비교할 수 있습니다. 폴리모피즘을 이용할 수 있도록 Protoss

레퍼런스로 프로그램 함으로써 같은 클래스의 객체만 비교할 수 있는 것이 아니라

모든 Protoss끼리는 비교할 수 있습니다.

Posted by
,