2016-10-12 6 views
3

私はワイルドカードを使い始めていて、Javaのジェネリックスでは経験がほとんどなく、問題を割り振っています。Java:ワイルドカードのジェネリックからジェネリックに割り当てるのが難しい

私はUserVariable<T>というカスタムジェネリッククラスを持っています。各UserVariableは、その型とその値の2つのことを認識しています。どちらも、構築時に予期されています。必要最小限の定義は次のようになります。

class UserVariable<T extends Comparable<T>> implements Comparable<UserVariable<T>> 
{ 

private T value; 
private final transient Class<T> type; 

public UserVariable(T value, Class<T> type) 
{ 
    this.value = value; 
    this.type = type; 
} 

public T getValue() 
{ 
    return value; 
} 

public Class<T> getType() 
{ 
    return type; 
} 

} 

私は地図に保存されているこれらのUserVariablesのコレクションを持っています。私はマップを定義する際にワイルドカードを使用して、さまざまなタイプのUserVariableをすべて1つのマップに格納できるようにしました。ここでの考え方は、私のソフトウェアのユーザーは、変数を作成し、それらに名前を与えているということで、ソフトウェアを格納することができます/キーとして変数名を使用してマップ内の変数を調べる:

class VarsMap { 

private ObservableMap<String, UserVariable<?>> userVars = FXCollections.observableHashMap(); 

public void setVariable(String name, UserVariable<?> variable) 
{ 
    userVars.put(name, variable); 
} 

public UserVariable<?> getVariable(String name) 
{ 
    return userVars.get(name); 
} 

} 

その後、私が持っていますこの変数の1つを取り出してその型を格納しようとするクラスです。私はClass<T>として定義され、UserVariable<T>getType()方法はClass<T>を返す必要があります...

class SimpleComparison<T extends Comparable<T>> { 

private StringProperty variableName = new SimpleStringProperty(""); 
private T comparisonValue; 
private transient Class<T> myVarType; 

public SimpleComparison(String variableName, T value, VarsMap theVars) 
{ 
    this.myVarType = theVars.getVariable(variableName).getType(); //error here 
} 

} 

this.myVarTypeを非常に最後の割り当てとのトラブルを抱えています。また、各UserVariabletypeは、各UserVariableが構築された時点で格納される。

型の不一致:しかし、最後の割り当ては次のエラーを与える地図UserVariable<?>のマップであるため、Class<capture#1-of ?>からClass<T>

に変換することはできませんおそらくこれはありますか?誰も私がここで間違っていることを知っていますか?ご協力いただきありがとうございます!

編集:

public int evaluate(VarsMap theVars) 
{ 
    UserVariable<T> lhs = theVars.getVariable(variableName); 
    UserVariable<T> rhs = new UserVariable<T>(comparisonValue, myVarType); 

    return lhs.compareTo(rhs); 
} 

私はと比較して、変数名と値を使用してSimpleComparisonオブジェクトを構築し、次のとおりです。最終的に私がやりたいことは、これを行いevaluate呼ばSimpleComparisonのメソッドを持っています。後でそのオブジェクトのevaluateを呼び出し、現在の変数値のマップを渡し、(Mapから取得した)変数の現在の値と、構築時に渡された比較値を比較し、結果を返します。

しかし、私はlhsrhsがタイプClass<T>のものであろうしながら、タイプClass<?>であることになるでしょうのでcompareToへの呼び出しが動作するか分かりません。これを私が意図している方法でやる方法はありますか?あるいは、ワイルドカードオブジェクトのコンテナ(この場合はMap)にオブジェクトをドロップすると、そのオブジェクトのタイプは常に失われますか?

答えて

1

ジェネリックは、コンパイラによって厳密に検査されます。だから、限り、あなたは、同じタイプのために他の実体化に各ジェネリックインスタンス化関連ニルを維持するよう、すべてが正常である:

MyGeneric<String> s1=... 
MyOtherGeneric<String> o1=... 
s1.doSomething(o1); 

あなたはタイプを混合しようとすると、問題が来る:

MyGeneric<String> s1=... 
MyOtherGeneric<Double> o1=... 
s1.doSomething(o1); // Error 

[OK]を、これはかなり明白です。あなたのケースでは、問題は似ています:どのようなタイプのものであろうと、いくつかの汎用インスタンシエーションを非汎用抽象化VarsMapに集めようとします。

したがって、非汎用抽象化VarsMapに含まれるオブジェクトを汎用オブジェクトClass<T>と混在させようとすると、コンパイラはその型が一致するかどうかをどのように判断できますか?コンパイラエラーが発生します。

UserVariableオブジェクトは既に名前で一致していますが、各変数は常に同じ型であると仮定していますので、このプログラムで作成したチェックに頼ることができます。単に方法getVariableと、単純なキャストにメソッドスコープのパラメータを追加します。

public <T extends Comparable<T>> UserVariable<T> getVariable(String name) 
{ 
    return (UserVariable<T>)this.userVars.get(name); 
} 

...そしてまた、あなたはそれを呼び出すどこ適切な型のパラメータ置換を追加:返信用

this.myVarType=theVars.<T> getVariable(variableName).getType(); 
2

問題はマップに異なるタイプのパラメータ(Class<Integer>Class<String>などを格納できる値)が含まれていることです。マップから値を取得すると、値の型パラメータがわからず、コンパイラがコンパイラによる安全でないキャストに関する警告を使用して、とは異なる型パラメータを使用してClass<T>値にキャストすることはできません(ただし、Class<T>(Class<T>) theVars.getVariable(variableName).getType()に明示的にキャストできます)。

+0

感謝を。元の投稿にフォローアップの質問を追加しました。私がしようとしていることが可能かどうか知っていますか? – skrilmps

+0

たとえば、型パラメータがマップから取得されたときにその型パラメータが何であるかを知ることはできませんが、オブジェクト自体は、構築時にプライベート変数として格納されているため、独自の型を認識します。その情報を利用することは可能ですか? – skrilmps

+0

@skrilmps、更新) –

関連する問題