LoginSignup
18
17

More than 5 years have passed since last update.

「特定のインターフェイスを実装した Class クラス」をジェネリクスで表現したい

Last updated at Posted at 2015-07-24

オブジェクトマッピングを実現するロジックを書いていたりすると Class クラスのインスタンスを扱うことがあります。
その Class に何かしらの条件を設けたいということもよくあります。

折角Javaを使っているのだから、型検査時に不正な値を弾くことができるとステキですよね。

実現したいこと

// 重要なインターフェイス!
interface MetaSyntacticValiable {}

class Hoge implements MetaSyntacticValiable {}
class Fuga implements MetaSyntacticValiable {}

// MetaSyntacticValiable とは無関係なクラス
class UnrelatedToHogeOrSomething {}

中略

someMethodUsingClassClass(Hoge.class);    // OK
someMethodUsingClassClass(Fuga.class);    // OK
someMethodUsingClassClass(UnrelatedToHogeOrSomething.class);    // NG! そしてNGであることを型検査で教えて欲しい

解決方法


public void someMethodUsingClassClass(Class<? extends MetaSyntacticValiable> klass) {

...

}

Class<? extends MetaSyntacticValiable> がキモでした。

T.class の型が Class<T> なので、Class<?> のワイルドカードに条件を加えてやることで、任意のインターフェイスを継承したクラスの Class インスタンスのみを代入する事ができます。

インターフェイスを extends する…というのがどうにももどかしいですが、こちらの stackoverflow の回答によると、「ジェネリクスの文脈においては extends も implements も変わらない」のだそうで。
(ただしジェネリクスの制約で使えるのは extendssuper のみ)

もっと型の条件を増やしたいときは?

残念ながら以下の書き方はできません。
条件に使えるのは一つの型だけのようです。

// コンパイル通らない
Class<? extends InterfaceOne, InterfaceTwo>

「それでも両方のインターフェイスを継承したクラスに限定したいんだ!」という場合は、一つのインターフェイスに統合する必要があります。

interface InterfaceOnePlusTwo extends InterfaceOne, InterfaceTwo {}

中略

// これはコンパイル通る
Class<? extends InterfaceOnePlusTwo>

ただし、 統合前のインターフェイスを個別に implements したクラスは受け付けなくなります。

void methodUsingClassClass(Class<? extends InterfaceOnePlusTwo> klass) { ... }


// Class<? extends InterfaceOnePlusTwo> ではない!
class ForArgumentOne implements InterfaceOne, InterfaceTwo {}

// よってNG.
methodUsingClassClass(ForArgumentOne.class);



// こちらは Class<? extends InterfaceOnePlusTwo>
class ForArgumentTwo implements InterfaceOnePlusTwo {}

// なのでOK.
methodUsingClassClass(ForArgumentTwo.class);

別にこれくらい受け付けてくれたって良いじゃないか…

参考

18
17
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17