Javaのジェネリクスと継承のいい関係の模索
継承関係のあるクラス系統にジェネリクスを導入するので苦労していたのですが
Comparableに関しては以下のように書けることに気付きました。
ジェネリクスの型パラメーターには具象クラスしか指定できないという
錯覚を持っていたのがこれまでハマっていた原因でした・・・。
Comparableの実装クラスが数多く必要だがcompareToメソッドの実装は
抽象クラスだけに持たせたいといったケースになります。
ComparableのcompareToメソッドの実装を持つ抽象クラスを以下のようにします。
自分自身をComparableの型パラメーターに指定するのがポイント。
なお、JDK1.5環境で動作するコードになります。
※指摘によりcompareTo、getKeyにfinal修飾子を追加しました
public abstract class LongKeyEntity implements Comparable<LongKeyEntity> { private final Long key; public LongKeyEntity(long key) { this.key = Long.valueOf(key); } public final int compareTo(LongKeyEntity o) { return key.compareTo(o.getKey()); } public final Long getKey() { return key; } }
そのサブクラス達。
public class Son extends LongKeyEntity { public Son(long key) { super(key); } } public class Daughter extends LongKeyEntity { public Daughter(long key) { super(key); } }
上記のような記述ならばサブクラスのインスタンス同士で比較が可能です。
抽象クラスを指定したListに一緒に入れる事もできます。
List<Object>に何でも詰め込めることを考えたら、当然ですね・・・。
import java.util.*; public class GenericsTest { public static void main(String[] args) { compare(1L, 2L); compare(1L, 1L); compare(2L, 1L); setList(); } private static void compare(long left, long right) { Son son = new Son(left); Daughter daughter = new Daughter(right); System.out.println("left = " + son.getKey() + ", right = " + daughter.getKey() + " -> compare result = " + son.compareTo(daughter)); } private static void setList() { List<LongKeyEntity> list = new ArrayList<LongKeyEntity>(); list.add(new Son(10L)); list.add(new Son(5L)); list.add(new Son(1L)); list.add(new Daughter(4L)); Collections.sort(list); for (LongKeyEntity each : list) { System.out.println("key = " + each.getKey()); } } }
コンパイルもとおり、実行結果は以下のようになります。
left = 1, right = 2 -> compare result = -1
left = 1, right = 1 -> compare result = 0
left = 2, right = 1 -> compare result = 1
key = 1
key = 4
key = 5
key = 10