9

Javaでこれがあるとします:

List<String> list = new ArrayList<String>();
list.getClass();

最後の式の型は ですClass<? extends List>。消去によりClass<? extends List<String>>. しかし、なぜそれができないのClass<? extends List<?>>でしょうか?

この式の結果を、このクラスが実際に何らかの情報を保持する変数に代入したい場合、チェックされていないキャストの警告生の型の警告の両方を回避する方法はありませんListか?

Class<? extends List> listClass = list.getClass(); // raw type warning
Class<? extends List<?>> listClass = (Class<? extends List<?>>) list.getClass(); // unchecked cast warning
4

2 に答える 2

7

ジェネリックが最初に導入されたとき、が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

正当化:

  1. このルールは raw タイプを導入します。Raw 型は、レガシー コードとやり取りする場合にのみ使用する必要があります。

  2. 新しいルールでは、ワイルドカードが導入されています。パラメータ化された型とワイルドカードの関係は、サブタイプ規則に基づいています。パラメータ化された型とワイルドカードの関係は、生の型変換に基づいています。

このバグは対処されず、今日まで未解決のままであり、次の反論があります。

この提案は、他のオブジェクトと互換性のないオブジェクト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()の変換がチェックされていないため、 で警告が表示されます。しかし、提案では、類似のコードはコンパイルされません:ListList<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()すでに行っていることです。

全体として、この提案は良いアイデアのように見えますが、複雑さが中程度で、見返りはかなり小さいものです。

(一部抜粋、一部誤字修正あり)

于 2013-09-15T21:37:12.200 に答える
-3

それはインターフェースであるため、インターフェースが に実装されListていることを確認できるかどうかはわかりません。役立つかもしれないこのリンクを見つけましListArrayList

私はこれを少しいじって、それを見つけました...

    Class<?> d = list.getClass();
    d.equals(ArrayList.class);

しかし、それがあなたが探しているものかどうかはわかりません...

幸運を!

于 2013-09-14T02:41:22.567 に答える