2017-06-12 15 views
1

特定のタイプのT2が渡されたときにオブジェクトTをT2にキャストしたいと思います。 T2はインタフェースTからのクラスであるため、T2の複数の実装が可能です。 キャスティングまでは、適切に起こっています。しかし、私は型キャストされた関数の関数にアクセスすることができません。私は間違って何かしていますか?ジェネリックパラメータを別のジェネリッククラス引数からキャストする方法はありますか?

protected <T, T2> SortedMap<Integer, T2> noNameFunction(List<T> things, T2 ts) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) ts); 
     sortedMap.put (as.getSequence(), as.getFunctionsFromCastedIbjectA()); 
    } 
    return sortedMap; 
} 

私は概念的にどこかに間違っていますか? この問題を解決するにはどうすればよいですか?

+0

'instaceof'を使ってみましたか? https://stackoverflow.com/questions/6601132/instanceof-keyword-usage – xsami

+0

ここであなたはt変数を使用していますか?あなたが何もキャストしてはいけませんジェネリックを使用するとき –

+0

のように思えます。ジェネリック医薬品を介してタバコを扱います。 –

答えて

3

asから、T2に課す制約に基づいてコンパイラがコンパイル時に決定できないメソッドを呼び出すことはできません。

T2にはObjectというものがありますので、toStringhashCodeなどのように宣言されたメソッドしか呼び出せません。かなり役に立たなくなります。

T2タイプ(したがってT)を絞り込んで、より具体的なクラスやインターフェイスを絞り込むことができれば、メンバメソッドにアクセスできます。例えば、T、つまりT2が保証されているとします。 Numberですので、intValueと電話することができます。私は実際TgetSequence方法を定義するいくつかのクラスであるためにあなたのコードに制限されていることを推測としておそらくあなたに、このようなgetSequenceなどT方法で問題を解決するだろう

SequenceContainerと呼ばれるとしましょう。

protected <T extends SequenceContainer, T2 extends T> SortedMap<Integer, T2> noNameFunction(List<T> things, T2 ts) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) t); 
     sortedMap.put (as.getSequence(), as.t2OwnMethod()); // fail to compile, due to the call to t2OwnMethod. 
    } 
    return sortedMap; 
} 

完全な解決策は、呼び出し元がメソッド内で呼び出す必要のあるT2コードを提供できるラムダを使用することです。

protected <T extends SequenceContainer, T2 extends T, X> SortedMap<Integer, X> noNameFunction(List<T> things, T2 ts, Function<T2, X> valueFunction) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) t); 
     sortedMap.put (as.getSequence(), valueFunction.apply(as)); // fail to compile, due to the call to t2OwnMethod. 
    } 
    return sortedMap; 
} 

私は第三のタイプXに返されたソートマップの値を一般化するには、この機会をとっているのお知らせ...これは単にT2ことができ、あなたが提供するどのようなラムダによってはコンパイル時にシームレスに解決されます。今、あなたは、t2OwnMethod戻っ...文字列が言うと仮定して、この署名を呼び出すような方法がある:

List<? extends SequenceContainer> scs = ...; 
SpecialSequenceContainer exampleSSC = ...; /// SpecialSequenceContainer extends 
SortedMap<Integer, String> option1 = noNameFunction(scs, exampleSSC, ssc -> ssc.t2OwnMethod()); 
// or 
SortedMap<Integer, String> option2 = noNameFunction(scs, exampleSSC, 
    SpecialSequenceContainer::t2OwnMethod); 

さて、二番目のパラメータ(exampleSSC)はかなり無駄です...ので、あなたは、単にそれを省略することができることを予告。

私たちは、さらにここに行くとJavaは、質問コードですべての作業を行うためにストリームを使用することができます:キーの衝突がある場合に(s1, s2) -> s1ラムダはそれだけではなることはないかもしれない、呼び出されることを

final SortedMap<Integer, String> result = myScs.stream() 
    .map(t -> (SpecialSequenceContainer) t) 
    .collect(SequenceContainer::getSequence, 
       SpecialSequenceContainer::t2OwnMethod, 
       (s1, s2) -> s1, 
       TreeMap::new); 

お知らせ大文字と小文字は区別されますが、値をマージする機能は必要ありません。

+2

私はあなたのアプローチが好きです、upvoted!私はいくつかのコメントしか持っていないだろう... 1)ジェネリック型 'T'を持つことは意味がないように思える。あなたのケースでは、これは 'SequenceContainer'でしょう。また、リストを 'List <? extends SequenceContainer> '2)値を抽出する関数のほかに、関数を使ってキーを抽出するので、メソッドはできるだけ一般的になります。ストリームでは、メソッドの必要はありません。 –

+2

@FedericoPeraltaSchaffner、yes '' List <? extends SequenceContainer> '' 'はより正確です...恐らく、実際のコードで、彼はさらにこのコードを型パラメータとして' '' T2''を定義する別のメソッドに囲むことができます。これは '' List '' '(そしてマップやキャストは消え去るでしょう)として書き直すことができます...コードが実際にT2のものを知るレベルまで。はい、あなたは正しいです( '' '' '')は、この時点ではむしろ意味がありません。元のコードから改善できることがいくつかありますが、私はちょうどカップルを指摘しました。 –

関連する問題