Comparable vs. Comparator


ComparableとComparatorはJavaコアAPIが提供する2つのインタフェースです.名前から、何かを何らかの方法で比較するために使われていると推測できます.しかし、それらはいったい何なのか、それらの間にはどのような違いがあるのだろうか.次の2つの例はこの質問に答えた.この例はHDTVの大きさを比較するために用いられる.次のコードを読み終えると、ComparableとComparatorの使い方がわかります.
1.Comparable
1つのクラスは、自分のオブジェクトと他のオブジェクトを比較するためにこのインタフェースを実現します.クラスが自分のインスタンスを比較するには、このインタフェースを実装する必要があります.そしてcompareTo()という方法を実現します.例:
class HDTV implements Comparable {
	private int size;
	private String brand;
 
	public HDTV(int size, String brand) {
		this.size = size;
		this.brand = brand;
	}
 
	public int getSize() {
		return size;
	}
 
	public void setSize(int size) {
		this.size = size;
	}
 
	public String getBrand() {
		return brand;
	}
 
	public void setBrand(String brand) {
		this.brand = brand;
	}
 
	@Override
	public int compareTo(HDTV tv) {
 
		if (this.getSize() > tv.getSize())
			return 1;
		else if (this.getSize() < tv.getSize())
			return -1;
		else
			return 0;
	}
}
 
public class Main {
	public static void main(String[] args) {
		HDTV tv1 = new HDTV(55, "Samsung");
		HDTV tv2 = new HDTV(60, "Sony");
 
		if (tv1.compareTo(tv2) > 0) {
			System.out.println(tv1.getBrand() + " is better.");
		} else {
			System.out.println(tv2.getBrand() + " is better.");
		}
	}

2.Comparator
いくつかのシナリオでは、クラスを比較可能にしたくないかもしれません.このようなケースでは、特定のプロパティ/フィールドに基づいてオブジェクトを比較したい場合は、Comparatorを使用します.例えば、身長や年齢などによって2人を比較することができます.
compare()メソッドを実装する必要があります.TVの大きさを別の方法で比較してみましょう.Comparatorで最も一般的なアプリケーションはソートです.CollectionsとArraysは、Comparatorに基づいてソートする方法を提供しています.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
 
class HDTV {
	private int size;
	private String brand;
 
	public HDTV(int size, String brand) {
		this.size = size;
		this.brand = brand;
	}
 
	public int getSize() {
		return size;
	}
 
	public void setSize(int size) {
		this.size = size;
	}
 
	public String getBrand() {
		return brand;
	}
 
	public void setBrand(String brand) {
		this.brand = brand;
	}
}
 
class SizeComparator implements Comparator {
	@Override
	public int compare(HDTV tv1, HDTV tv2) {
		int tv1Size = tv1.getSize();
		int tv2Size = tv2.getSize();
 
		if (tv1Size > tv2Size) {
			return 1;
		} else if (tv1Size < tv2Size) {
			return -1;
		} else {
			return 0;
		}
	}
}
 
public class Main {
	public static void main(String[] args) {
		HDTV tv1 = new HDTV(55, "Samsung");
		HDTV tv2 = new HDTV(60, "Sony");
		HDTV tv3 = new HDTV(42, "Panasonic");
 
		ArrayList al = new ArrayList();
		al.add(tv1);
		al.add(tv2);
		al.add(tv3);
 
		Collections.sort(al, new SizeComparator());
		for (HDTV a : al) {
			System.out.println(a.getBrand());
		}
	}
}

また、Collections.reverseOrder()を使用して、逆シーケンス比較器を取得することもできます.次のようになります.
ArrayList al = new ArrayList();
al.add(3);
al.add(1);
al.add(2);
System.out.println(al);
Collections.sort(al);
System.out.println(al);
 
Comparator comparator = Collections.reverseOrder();
Collections.sort(al,comparator);
System.out.println(al);

3.選択方法
簡単に言えば、クラスがComparableインタフェースを実装すると比較されます.つまり、そのインスタンス間で比較することができます.
クラスは主に2つのケースでComparatorインタフェースを実装しています.1)Collections.sort()やArrays.sort()のようなソート方法に伝達し、ソート方法を正確に制御することができます.2)TreeSetやTreeMapなど、特定のデータ構造の並べ替えを制御するためにも使用できます.
たとえば、TreeSetを作成したり、そのコンストラクタにcomparatorを渡したり、comparableインタフェースを実装したりします.
実装1(comparatorを使用)
class Dog {
	int size;
 
	Dog(int s) {
		size = s;
	}
}
 
class SizeComparator implements Comparator {
	@Override
	public int compare(Dog d1, Dog d2) {
		return d1.size - d2.size;
	}
}
 
public class ImpComparable {
	public static void main(String[] args) {
		TreeSet d = new TreeSet(new SizeComparator()); // pass comparator
		d.add(new Dog(1));
		d.add(new Dog(2));
		d.add(new Dog(1));
	}
}

実装2(comparableを使用)
class Dog implements Comparable{
	int size;
 
	Dog(int s) {
		size = s;
	}
 
	@Override
	public int compareTo(Dog o) {
		return o.size - this.size;
	}
}
 
public class ImpComparable {
	public static void main(String[] args) {
		TreeSet d = new TreeSet();
		d.add(new Dog(1));
		d.add(new Dog(2));
		d.add(new Dog(1));
	}
}