2016-03-22 7 views
2

私はいくつかの型Tのオブジェクトを取り込むジェネリックメソッドとその型を表すクラスを持っていたいと思います。最終的にはこれを使用してMap<Class<?>, Object>を作成する予定です。そこでは、各クラスが正確に独自の型のオブジェクトにマップされることがわかります。私はこれをコンパイラに説得することはできませんが、できる限り多くのコードに対してコンパイル時の一般的な安全性を維持したいと思います。私は問題なくfooメソッドを書くことができ、そしてそれは私が欲しい署名を持っている、と私は正確に何種類のIを知っていれば、私はそれを使用することができますjavacはx.getClass()とxを一緒に使用するための適切なジェネリックを推論できますか?

public class Example { 
    public static <T extends Number> void foo(Class<T> c, T x) { 
    ; 
    } 

    public static void bar(int x) { 
    foo(Integer.class, x); 
    } 

    public static void baz(Number x) { 
    foo(x.getClass(), x); 
    } 
} 

:ここで私はに実行している問題を実証する最小限の例です。 barのように、コンパイル時に持っているが、私はbazにしようとして、私は、任意の型のオブジェクトにそれを使用することはできません。bazコンパイルされません、引用:

Example.java:11: error: method foo in class Example cannot be applied to given types; 
    foo(x.getClass(), x); 
    ^
    required: Class<T>,T 
    found: Class<CAP#1>,Number 
    reason: inferred type does not conform to lower bound(s) 
    inferred: CAP#1 
    lower bound(s): Number 
    where T is a type-variable: 
    T extends Number declared in method <T>foo(Class<T>,T) 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends Number from capture of ? extends Number 

私はここでの問題を理解すると思います:x.getClass()Class<? extends Number>を返します。<? extends Number>Tであるが、xのタイプはNumberであり、TNumberである必要があります。私がこれを書いたとき、私はコンパイラがx.getClass()xが全く同じTを共有することを知っていることを期待していましたが、それはそれを知ることができません。

ここで私は何をしますか? fooのようなものと、bazのようなものを書くことができる方法はありますか?私はコンパイル時の安全性を放棄し、実行時にいくつかのキャストを行うべきですか? Map<Class, Object>の私の最終目標に近づくための良い方法がありますか?

+0

'バーを(int型x)'は、なぜそれが 'バー(数x)ではありません' – Tgsmith61591

+0

これは 'クラスからfoo'の最初のパラメータ'かの変更をコンパイルすることができますか? 'を' Class 'に変更します。 – rgettman

+0

@rgettmanしかし、それは私が*許可したくない他のものを許可します。私の目標は、クラスとオブジェクトが同じであることを強制することです。スーパークラスをキーとして、またはそのサブクラスの1つをキーとしてオブジェクト参照をvalとして格納することはできません。 – amalloy

答えて

1

the documentation for Object.getClass()によると:

実際の結果型がありますClass<? extends |X|>ここで、|X|は、の式の静的型の消去ですが呼び出されます。

「静的タイプの消去」に関する部分に注意してください。つまり、タイプ変数Tが宣言されている場合(たとえば、<T extends Number>)、変数がT xの場合、x.getClass()の戻り値はではなく、Class<? extends Number>となります。それは確かに、安全でないキャストなしであなたがしたいことをするのを難しくします(確かに、あなたがしたいことが何であるかによって異なります)。

ただし、独自の機能に安全ではない場合があります。たとえば、これは動作します:

public class test { 
    public static <T extends Number> void foo(Class<T> c, T x) { 
     ; 
    } 

    @SuppressWarnings("unchecked") 
    public static <T> Class<? extends T> getClass2(T x) { 
     return((Class<? extends T>)x.getClass()); 
    } 

    public static void bar(int x) { 
     foo(Integer.class, x); 
    } 

    public static void baz(Number x) { 
     foo(getClass2(x), x); 
    } 
} 
0

できませんでしたか?

public static class Example { 
    public static <T extends Number> void foo(Class<? extends T> c, T x) { 
     ; 
    } 

    public static void bar(int x) { 
     foo(Integer.class, x); 
    } 

    public static void baz(Number x) { 
     foo(x.getClass(), x); 
    } 
} 

あなたはfoo(Class<T> c, T x)としてfoo署名を維持する上deadsetなら、bazは次のように変更する必要があります。

@SuppressWarnings("unchecked") 
public static <T extends Number> void baz(T x) { 
    foo((Class<T>)x.getClass(), x); 
} 
関連する問題