ジェネリックが最初に導入されたとき、がgetClass
返されました。Class<? extends X>
ここX
で、 は呼び出された式の静的な型です。このOracle バグで報告されているように、この動作は不合理なコンパイルの問題を引き起こしました。そのバグレポートの例は次のとおりです。
次のプログラム フラグメントはコンパイルに失敗します。
void f(List<Integer> li, List<String> ls) {
if (li.getClass() == ls.getClass())
;
}
Class<List<Integer>>
と
の交点Class<List<String>>
は空だからです。
この問題は、戻り値の型を現在の型に拡大することで解決されましたgetClass
。ドキュメントから:
実際の結果の型はClass<? extends |X|>
、が呼び出さ|X|
れた式の静的型の消去です。getClass
これにより上記の問題は解決しましたが、その結果、質問が指摘する問題が発生しました。その後まもなく、別のバグが報告され、次のように主張されました。
getClass()
タイピングルールは次のように変更できると思いますClass<? extends
wildcard(T)>
ワイルドカード操作は次のように定義されT
ます
wildcard(T)=erasure(T)<?>
。
wildcard(T)=T
正当化:
このルールは raw タイプを導入します。Raw 型は、レガシー コードとやり取りする場合にのみ使用する必要があります。
新しいルールでは、ワイルドカードが導入されています。パラメータ化された型とワイルドカードの関係は、サブタイプ規則に基づいています。パラメータ化された型とワイルドカードの関係は、生の型変換に基づいています。
このバグは対処されず、今日まで未解決のままであり、次の反論があります。
この提案は、他のオブジェクトと互換性のないオブジェクトgetClass()
を返すことを意味します。これは、次のような既存のコードと互換性があります。 Class<? extends
ArrayList<?>>
Class<? extends
ArrayList<?>>
List<String> l = ...;
Class<? extends List> c = l.getClass();
RHS の新しいタイプClass<? extends List<?>>
は のサブタイプであるためです
Class<? extends List>
。
Class の型引数を充実させることの欠点は、慣用的なClass.cast
. 今日、あなたは書くことができます:
List<Integer> x = ...;
Class<? extends List> cl = x.getClass();
List<Integer> y = cl.cast(null);
からへcast()
の変換がチェックされていないため、 で警告が表示されます。しかし、提案では、類似のコードはコンパイルされません:List
List<Integer>
List<Integer> x = ...;
Class<? extends List<?>> cl = x.getClass();
List<Integer> y = cl.cast(null);
List<?>
によって返されるため、cast()
に変換できませんList<Integer>
。このエラーを回避する唯一の方法は、 にキャスト
cl.cast(..)
してList
、 への未チェックの変換警告を受けること
List<Integer>
です。これは事実上、getClass()
すでに行っていることです。
全体として、この提案は良いアイデアのように見えますが、複雑さが中程度で、見返りはかなり小さいものです。
(一部抜粋、一部誤字修正あり)