web-dev-qa-db-ja.com

タイプパラメータが指定されていないのに、なぜJavaジェネリックrawクラスはオブジェクトへのすべてのジェネリックを消去するのですか?

クラスがある場合:

_public class GenericClass<TBlah extends Number> {
    public List<String> getList() {
        return null;
    }
}
_

別のクラスからそのメソッドを使用しようとすると、次のようになります。

_public class OtherClass {
    public void test() {
        GenericClass a = null;
        for (String s : a.getList()) {

        }
    }
}
_

Forループの上の行を次のように変更するまで、a.getList()が_List<Object>_を返すのはなぜですか。

_GenericClass<Number> a = null;
_

どの時点で、a.getList()は_List<String>_を返す必要がありますか?

編集:getList()で指定されたコントラクトが、変数「a」の宣言方法によって影響を受ける理由がわかりません。 getList()は常に_List<String>_を返しますが、TBlahが何であるかは関係ありません。

21
Xenoprimate

これがジェネリックスの仕組みだからです。ジェネリックスの前にListを宣言したとき、それはObjectのリストであったことを忘れないでください。 Objectを置く/取得することが期待されていたため、正しいタイプのオブジェクトを取得するためにキャストする必要がありました。実際には、それでも実行時のObjectのリストです。

ジェネリックスは、警告がないと仮定して、コンパイル時に安全性を入力することをコンパイラーが保証する方法です。実行時に_List<String>_はありません。 Listだけがあります。コンパイラーが自動キャストを提供するため、コード内でキャストせずにString s = list.get(i)を記述できます。

_GenericClass a_を宣言すると、生の型を宣言することになります(これについては警告が表示されます)。したがって、コンパイラには、a.getList()が返すことになっている型を知る方法がありません。したがって、Objectを使用します。 _GenericClass<Number> a = null;_を宣言すると、コンパイラはa.getList()に期待されるタイプを認識し、目的のタイプを使用します。

編集:コンパイラは、署名のコントラクトを尊重する場合にのみ(つまり、_GenericClass<Number>_の場合のように)何を期待できるかを知ることができることを明確にする必要があります。コントラクトを尊重しない場合(つまり、_extends Number_を使用しないrawタイプを使用している場合)、コントラクトは適用されなくなります。コンパイラは、型情報が存在しないかのように動作します。コンパイラーは、ジェネリックス以前の時代に作成されたコードとの下位互換性も維持する必要があることを忘れないでください

13
c.s.