23

クラスがある場合:

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()するまで、 a が返されるのはなぜですか。List<Object>

GenericClass<Number> a = null;

どの時点で a.getList() が返すList<String>必要がありますか?

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

4

1 に答える 1

15

これがジェネリックの仕組みだからです。Listジェネリックの前に a を宣言したとき、それは のリストだったことを忘れないでくださいObject。put/get が期待されて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)、コントラクトは適用されなくなります。コンパイラは、型情報が存在しないかのように動作します。コンパイラはジェネリック以前の時代に作成されたコードとの後方互換性も維持する必要があることを忘れないでください。

于 2013-07-19T10:30:52.347 に答える