2012-01-05 18 views
5

Eclipseはジェネリック・タイプの消しゴムのためにタイプ・パラメーターでinstanceof操作が許可されていないと言います。Tが型パラメータでtが変数の場合、なぜ "t instanceof T"は許されないのですか?

私は、実行時にタイプ情報が残っていないことに同意します。しかし、次のクラスの一般的な宣言を考えてみましょう:

class SomeClass<T>{ 
    T t; 
    SomeClass(Object o){ 
     System.out.println(o instanceof T); // Illegal 
    } 
}   

実行時には、Tは存在しません!しかし、このクラスのIntegerをインスタンス化すると、対応するオブジェクトはInteger型のフィールドtを持ちます。

次に、実行時にIntegerに置き換えることができるTの変数の型をチェックできません。そして、私は実際に "o instanceof Integer"のようなことをしています。

この場合、タイプパラメータを持つinstanceofを許可すると、トラブルが発生して禁止されますか?

+7

あなたはすでに「実行時にはTは存在しません」と言っていますので、既にタイプ消去を認識しているようですね。だから私はあなたがなぜこの行動について混乱しているのか分かりません。 –

+1

それは許可されていないという理由だけでルーブルを引き起こす可能性があるからです。 Tはジェネリック型であり、実際には何でも構いません。 – Peter

+0

[Java:Instanceof and Generics]の重複可能性(http://stackoverflow.com/questions/1570073/java-instanceof-and-generics) – millimoose

答えて

3

ステートメントo instanceof Tをコンパイルすると、o instanceof Objectとなり、すべての型がObjectから派生するため、常にtrueに評価されます。この種のテストを許可すると、誤った結果が得られます

0

ジェネリック型の引数は実行時には分かりませんので、比較できるクラスはありません。 Tはコンパイル時にのみ知られています。ジェネリックスは、開発者がコードを簡単に書くのに役立ちます。しかし、実行時に引数はただObjectインスタンスです。

4

実行時にTが必要な場合は、実行時に提供する必要があります。これは多くの場合、Tが必要なクラス< T>を渡すことによって行われます。

class SomeClass<T> { 
    final T t; 

    public SomeClass(Class<T> tClass, T t) { 
     if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass); 
     this.t = t; 
    } 

    private SomeClass(T t) { 
     this.t = t; 
    } 

    public static <T> SomeClass<T> of(Class<T> tClass, T t) { 
     if(!tClass.isAssignableFrom(t.getClass()) throw new IllegalArgumentException("Must be a " + tClass); 
     return new SomeClass(t); 
    } 
} 

// doesn't compile 
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, "one"); 

Class clazz = Integer.class; 
// compiles with a warning and throws an IAE at runtime. 
SomeClass<Integer> intSomeClass = (SomeClass<Integer>) SomeClass.of(clazz, "one"); 

// compiles and runs ok. 
SomeClass<Integer> intSomeClass = SomeClass.of(Integer.class, 1); 
3

type erasureのため、これは決して動作しません。実行時には、クラスに型パラメータTがありますが、指定されたインスタンスの型はありません。したがって、オブジェクトがTの型であるかどうかは、Tが何であるか分からないために判断できません。何らかの問題を引き起こすものではありません。

SomeClass(Object o, Class<T> type) { 
    System.out.println(type.isInstance(o)); 
} 
1

をしかし、私はInteger型のこのクラスをインスタンス化した場合、対応するオブジェクトがあります:あなたは、ランタイムチェックのこの種を行う必要がある場合

、明示的にオブジェクトに型トークンを渡しますInteger型のフィールドt。

実際、そうではありません。フィールドtObjectです。あなたが言ったように、ジェネリックスはほとんど完全に構文的な砂糖です(ただし、ジェネリッククラスを拡張して型パラメータを指定すると、その型はクラスファイルのメタデータのままです)。

6

しかし、私はInteger型のこのクラスをインスタンス化した場合、その後、 対応するオブジェクトはInteger型

ないのフィールドtを持っていますが、それはしません。 Object型のフィールドを持ちます。アクセスするたびにIntegerにキャストされます。

SomeClass<Integer> c = new SomeClass<Integer>(); 
SomeClass untyped = (SomeClass)c; // Which type was it? 
SomeClass<String> stringTyped = (SomeClass<String>)untyped; // Now it's STRING?? 

作品:

は、次のコードを考えてみましょう。あなたにコンパイラ警告の束を与えますが、動作します。フィールドTは実際にはObject型であり、何にでもキャストすることができるからです。

0

Javaはで「実行時間」そこにのみBOUNDARIES型パラメータの、それは型をチェックし、「コンパイル時間」タイプのパラメータ情報を削除することができ、「消去」を使用して、そのジェネリックを実現します"Integer"のようなものはありません

関連する問題