次の 2 つのメソッド宣言を検討してください。
1. public abstract <T extends MetaData> List<T> execute();
2. public abstract List<? extends MetaData> execute();
どちらもMetaData を拡張するオブジェクトのリストを返すようです。
それらの違いは何ですか?
最初のケースでは、Java が型推論を使用T
し、各呼び出しサイトでの型を推論できるようにします。
2 番目のケースでは、常に aList<? extends MetaData>
を取得するため、 のようなより狭い型の変数に割り当てることはできませんList<IntegerMetaData>
。
のサブタイプがあるMetaData
場合、最初のバージョンは空のリストまたは のみを返すことができnull
ます。MetaData
2 番目のバージョンは、 のインスタンスとそのサブタイプを含むリストを返す場合があります。
例: A
andB
は のサブタイプでMetaData
ありexecute
、 のインスタンスを含むリストを返しますA
。呼び出し元は次のように execute を呼び出した可能性があります。
List<B> list = execute(); // the second version does not allow this
発信者は、 のリストが必要だと言いましB
たが、 を含むリストを取得しましたA
。型の消去により、 の実装でexecute
は、呼び出し元が何を要求したかを知る方法がありません。したがって、最初のバージョンは実装できません (returnnull
または空のリストを除く)。
例 1 では、ジェネリック型が である List を返す必要はありませんT
。
@Override
public <T extends MetaData> List<T> execute() {
List<T> l = new ArrayList<T>();
return l;
}
例 2 では、ジェネリック型が justMetaData
である List を返すことができます。
@Override
public List<? extends MetaData> execute2() {
List<MetaData> l = new ArrayList<MetaData>();
return l;
}
違いはなんですか?最初のケースでは、メソッドにはジェネリック型があり、その型に関連する何かを返す必要T
があります。2 番目のケースでは、ジェネリック型を返すだけですが、メソッド自体にはジェネリック型がありません。