8

次の Java ジェネリックの簡単な例を見てください。

class List<T> {
    T head;
    List<T> next;
}

class A<T> {
    List<T> l;

    public <T> int length() {
        List<T> l = this.l;
        int c = 1;
        while (l.next != null) {
            c++;
            l = l.next;
        }
        return c;
    }

    public static void main(String[] args) {
        A<Integer> a = new A<Integer>();
        a.l = new List<Integer>();
        a.l.head = 123;
        a.l.next = new List<Integer>();
        a.l.next.head = 432;
        System.out.println("list length: " + a.length());
    }
}

型に互換性がないことを主張しながら、2 つの変数が同じ型であると主張するコンパイル エラーが発生します。

$ javac A.java && java A
A.java:10: incompatible types
found   : List<T>
required: List<T>
        List<T> l = this.l;
                        ^
1 error

length() の最初の行を に変更するとList<T> l = (List<T>)(Object)this.l;、機能します。なんで?

4

1 に答える 1

19

次の行で、ジェネリック クラス内でジェネリック メソッドを宣言しました。

public <T> int length() {

これ<T>はあなたのクラスのものとは異なります<T>JLS セクション 6.3によると:

クラスの型パラメーターのスコープ (§8.1.2) は、クラス宣言の型パラメーター セクション、クラス宣言のスーパークラスまたはスーパーインターフェイスの型パラメーター セクション、およびクラス本体です。

<T>メソッドで再宣言する必要はありません。クラスの型パラメーターは既にスコープ内にあります。

クラスのジェネリック型パラメーターを使用する<T>には、メソッドで別の型を宣言せず<T>、単にクラスの を使用します<T>

public int length() {

キャストが機能する理由を理解するには:

List<T> l = (List<T>)(Object)this.l;

に任意のオブジェクトをキャストできますObject。次に、結果を にキャストしていList<T>ます。いつでも好きなようにキャストできます。ClassCastExceptionJava は、実行時に実際に でなかった場合、単純に実行時に をスローListします。ただし、コンパイラは、これ<T>が元の<T>.

<T>sの違いを説明する<U>ために、メソッドのジェネリック型パラメーターとして使用して、同じ結果を得ることができます。

public <U> int length() {
    List<U> l = (List<U>)(Object)this.l;

これは、同じ型安全警告でコンパイルされます。

型の安全性を保証できることが本当にわかっている場合は、 を使用@SuppressWarnings("unchecked")してメソッドに注釈を付けることができます。しかし、ここでは、ジェネリック型パラメーターをメソッドから完全に削除し、クラスの型パラメーターを使用します。

于 2013-06-24T18:32:37.440 に答える