型パラメータの扱いの困ったところ。
Genericsの型パラメータはコンパイラへの情報伝達に過ぎないらしく、実行時に「パラメータとして何のクラスが渡されたか」の情報は持っていないご様子。そのせいか何かわからんが、とにかくオーバーロード*1時にちょっと困ったことになる。
元ネタはServiceのAPIをどげんかせんといかん - うなの日記。いつもお世話になってます。
こう使いたい!
違うクラスのID同士を比較した場合、「違う」と通知してほしいので、↓のようなテストケースを書いた。
ID<Hoge> hogeID = new ID<Hoge>(123); ID<Fuga> fugaID = new ID<Fuga>(123); assertFalse(hogeID.equals(fugaID));
で、対応するIDクラスの中で↓のように書いた。
@Override public boolean equals(Object obj) { if (obj instanceof ID) { ID<E> that = (ID<E>) obj; //warning return this.id.equals(that.id); } return false; }
が、テスト不合格。objからthatにキャストする部分で型パラメータは無視してしまうらしい。かといって(obj instanceof ID
悩んだ挙句、↓にした。
@Override public boolean equals(Object obj) { return false; } public boolean equals(ID<E> that){ if(that!=null) return this.id.equals(that.id); return false; }
これで、hogeID.equals(fugaID)からhogeID.equals(Object)が呼ばれるようになり、意図通りの動作になった。
めでたしめでたし。だが…。
気になったので試したが、↓はエラー
@Override public boolean equals(Object obj) { return false; } public boolean equals(ID<E> that){ if(that!=null) return this.id.equals(that.id); return false; } public boolean equals(ID<String> that){ return false; }
実行時には型パラメータの違いでクラスは区別されないため、エラーとなる。こりゃ何か気持ち悪い。
*1:この単語を使うのは初めてだw