2011-01-16 8 views
2

Javaで奇妙なエラーこれはokです:ジェネリック

Class<? extends String> stringClass = "a".getClass(); 

しかし、これはエラーを取得します。

<T> void f(T obj) { 
    Class<? extends T> objClass = obj.getClass(); 
} 

私は同じようにキャストすることができます知っている:

<T> void f(T obj) { 
    @SuppressWarnings("unchecked") 
    Class<? extends T> objClass = (Class<? extends T>) obj.getClass(); 
} 

しかし、なぜ以前のエラー? Java 7の次のリリースではそのような使用法がサポートされる予定ですか?

EDITは

私は型消去を扱う問題はない、と私のコードは正しいですが、コンパイラはそれをサポートしていない時はいつでもちょうど余分SuppressWarningsを置きます。

背後にある質問はSuppressWarningsで十分ではありません。 T.getClass() => ? extends Tが明らかに直感的な場合、なぜ警告を抑制する必要がありますか?

すでにjavadocの見てきたように:私たちは、Javaのジェネリックについて話すとき

The actual result type is Class where |X| is the erasure of the static type of the expression on which getClass is called.

Object.getClass()は特殊なケースです。これは、宣言されたフォームとは異なり、ちょうどClasss<?>を返します。 Eclipse IDEのようなIDEがどのように実装されているのか分かりませんが、Eclipse IDEで完成するとClass<?>の代わりにClass<? extends |X|>が生成されます。私は基本クラスを作るために、Objectクラスにいくつかの魔法のものがあると思いますか?派生型から拡張され、派生型間で異なる。したがって、Java言語で独自のObjectクラスを作成することはできません。? extends |X|のようなものが返されます。|X|this.getClass()です。しかし、JavaのObjectは、特別なケースです。

答えて

1

the Javadocを見ると、これはObject.getClass()のための署名です:

public final Class<?> getClass() 

それは

クラスリテラルはセクション15.8.2 in the JLSで定義されていると言うことになります。最初のケースで

"a".getClass()の静的タイプはStringので、getClass()の戻り型はClass<? extends String>あります。後者の場合には、objの消去はObjectなので、戻り値の型は"a".getClass()Class<String>を返さない理由だけでClass<?>

あなたは不思議に思われるかもしれない本当にあるClass<? extends Object>です。結局、コンパイラは "a"がStringであることを "知っている"。その理由は、Classを汎用化したときにはTのクラスを表し、Tのサブタイプのクラスではないと判断しました。 getClassの署名は、その決定から落ちると継承の結果:あなたはgetType(Long.valueOf(123)を呼び出す場合

<T> Class<? extends Number> getType(Number obj) { 
    return obj.getClass(); 
} 

それはClass<? extends Number>を返します。式"a"は、タイプStringのオブジェクトです。 TがExceptionであれば一貫性を保つため、"a".getClass()は、例えばClass<? extends String>

2

Classは、Java言語ではなくJVM内のクラスを表します。したがってList<String>の場合、実際のClassClass<List>です。あなたの例では、TList<String>の場合、はObject.getClass APIドキュメントに記載されているようにClass<? extends List>を返します。

+0

これは間違いありませんが、OPが尋ねる問題は、2番目の例がコンパイルされない理由です: 'found:java.lang.Class required:java.lang.Class 'を継承します。 –

1

type erasureのためです。最初のケースでは、実際の具体的なタイプがありますので、.getClass()が成功します。 2番目のケースでは、objの実際のタイプは実行時に消去されるので、.getClass()Objectより良くできません。

改正ジェネリックがこれを修正します。 Alex Miller's blogによれば、この機能はJava 7には存在しません。この質問もasked here on StackOverflowでした。

0

<? extends T> Tの特定のサブタイプを意味し、

を返す必要があり、<? extends T>RuntimeException又はSQLExceptionことができます。 T.getClass()がRuntimeExceptionSQLExceptionかどうかはわかりません。だから、明示的なキャストが必要です。 getClassため

1

宣言された戻り値の型はそう、残念ながら、コンパイラは唯一getClass<? extends T>のキャプチャと同じではありません<? extends Object>のキャプチャを返すことを知っているClass<?>です。 javadocから

明示的なキャストとのバージョンが動作する理由です
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. 

最初の例では、コンパイラはオブジェクトの静的型がStringであることを知っているので、期待通りにキャプチャを実行できます。あなたはは、次の操作を行うことができます

注:

public static <T extends Number> void f(T obj) { 
    Class<? extends Number> objClass = obj.getClass(); 
} 

我々はTの静的な型がNumberのサブクラスであることを保証することができますので