2011-12-09 12 views
9

タイプの消去を回避し、タイプパラメータにアクセスできる方法はありますか?Javaタイプの消去を避ける

public class Foo<T extends Enum<?> & Bar> { 
    public Foo() { 
     // access the template class here? 
     // i.e. : 
     baz(T.class); // obviously doesn't work 
    } 

    private void baz(Class<T> qux) { 
     // do stuff like 
     T[] constants = qux.getEnumConstants(); 
     ... 
    } 
} 

私はTについて知っている必要があります。それが可能かどうか、そうであればなしでコンストラクタ内のクラスに渡すか、パラメータ以外の場所でどのように行うことができますか?

EDIT:この質問の主な目的は、型消去周り任意の実用的な方法があるかどうかを確認することです。

答えて

5

AFACTあなたはランタイムがアクセス権を持っていない何かを求めることはできませんので、型消去周り実用的な方法はありません。もちろん、Barインターフェイスを実装する各列挙体の汎用クラスをサブクラス化することは実際的な回避策であると考えています。

enum Test implements Bar { 
    ONE, TWO 
} 

class Foo<T> extends FooAbstract<Test> { 
    public Foo() { 
     ParameterizedType genericSuperclass = 
       (ParameterizedType) getClass().getGenericSuperclass(); 
     baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]); 
    } 

    private void baz(Class<T> qux) { 
     T[] constants = qux.getEnumConstants(); 
     System.out.println(Arrays.toString(constants)); // print [ONE, TWO] 
    } 
} 

interface Bar { 
} 

class FooAbstract<T extends Enum<?> & Bar> { 
} 
+2

+1これは、 'Class'オブジェクトを継承するためにサブクラス化する方が好きなら、これは別のリフレクションベースの方法です。 –

2

あなたはクラスのコンストラクタにトークン渡しすることができ/喜んでいる場合:

public Foo(Class<T> clazz) { 
    baz(clazz); 
} 

private void baz(Class<T> qux) { 
    // ... 
} 

こうすることで、あなたはClass.newInstance()に任意のオブジェクトをキャストしようとすると、T型のオブジェクトを生成することができますがT. Class.cast()などを使用します。

baz()で何をしますか?

+0

与えられたクラスに値のリストを要求し、それらの値を使用しているとします。クラスに合格することは、私がしたいことではありません。 –

1

回答者が指摘したように、これを達成する唯一の方法は、タイプTを表すClassオブジェクトを渡すことです。 が実行時に消去されるため、T.classのようなものはありません。Type Erasureが原因です。

Classオブジェクトには耐性がありますが、方法getEnumConstants()を使用する唯一の方法です。ここでは自己完結型の例である:

public class Foo<T extends Enum<?> & Bar> { 

    final Class<T> clazz; 

    public Foo(Class<T> clazz) { 

     this.clazz = clazz; 
    } 

    public void baz() { 

     T[] constants = clazz.getEnumConstants(); 

     System.out.println(Arrays.toString(constants)); 
    } 

    public static void main(String[] args) { 

     new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]" 
    } 
} 

public interface Bar { } 

public enum MyEnum implements Bar { A, B, C, D; } 
+2

タイプ消去を回避し、クラスが 'T 'として渡されることは絶対にありません。このスレッドのアイデアは、タイプ消去の周囲に何か方法があるかどうかを調べることです。 –

+1

@Chris - リフレクションは、Javaで消去を行う唯一の回避策です。しかし、あなたは 'Class'オブジェクトを渡すことによってあなたが持っているものから不利にならないようにします。コンパイル時に迷惑で冗長に見えますが。既にClass#getEnumConstants()を使ってリフレクションに頼っていることに注目してください。唯一の選択肢は、そのメソッドへの依存を取り除く完全な再設計です。 –

1

Neil Gafterによって提案されたスーパータイプのトークンを使用し、この目的のためにguiceのようなライブラリで使用されます。

元の説明はhttp://gafter.blogspot.com/2006/12/super-type-tokens.htmlを参照してください。私は、CAラジオライフの実装のためのguiceソースをチェックしています。

あなたはリチャード・ゴメスによって提案された回避策を使用することができますいくつかのケースでは、インラインここHow can I pass a Class as parameter and return a generic collection in Java?

0

働いた例とその答えを持っている別のqがあります。 匿名クラスのインスタンスを作成する場合は、型パラメータのクラス情報を使用できます。

class A<T> 
{ 
    A() 
    { 
     java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType) (this.getClass().getGenericSuperclass()); 
     System.out.println(parameterizedType.getActualTypeArguments()[0]); 
    } 
} 

public class Example { 
public static void main(String[] args) { 
    A<String> anonymous = new A<String>() {}; // prints java.lang.String 
} 
} 

この方法で作成された複数のインスタンスが異なる匿名クラスのものであろうと、それが問題だ場合は、新しいへの呼び出しを置き換えるために、クローンに基づくcreateNew()関数を持つクラスA_String_Factoryをしたい場合があります。

関連する問題