ワイルドカードのパラメータ化された型を返すコードがあります。これをパラメトリックメソッドに渡そうとしていますが、コンパイラエラーが発生します。誰かがなぜタイプが一致しないのかを私に説明することができますか?これを解決する最も良い方法は何ですか?Java 2レベルのパラメータ化された型の推論
static <L extends List<T>,T extends Number>
void useList(List<L> list) {}
public static void main(String[] args) {
List<List<? extends Number>> list = null;
useList(list);
}
コンパイルエラー:私の実際のコードlist
で
demo/GenericsHell.java:75: error: method useList in class GenericsHell cannot be applied to given types;
useList(list);
^
required: List<L>
found: List<List<? extends Number>>
reason: inference variable L has incompatible bounds
equality constraints: List<? extends Number>
upper bounds: List<CAP#1>
where L,T are type-variables:
L extends List<T> declared in method <L,T>useList(List<L>)
T extends Number declared in method <L,T>useList(List<L>)
where CAP#1 is a fresh type-variable:
CAP#1 extends Number from capture of ? extends Number
1 error
は、「リスト」(実際にはカスタムジェネリッククラス)のいくつかのタイプを返すことができ、複雑な方法によって生成されています。タイプセーフな方法でこれを受け入れるように、useList関数をパラメータ化する別の方法がありますか?
編集1
私は簡潔で、コヒーレント質問へのコードの大規模なモジュールを軽減しようとしています。答えから私は上記のコードが私が持っている正確な問題を単純化し過ぎていることがわかります。もっと複雑な例を挙げてみようと思いますが、私の制約を明確にしています。
まず、私は実際にリストを使用しているのではなく、二重のパラメータ化を使用するより複雑なクラスです。私はこれを行う任意の標準クラスを考えることはできませんので、私は例で使用するものを定義します:
static class NumberLists<L extends List<T>,T extends Number> extends ArrayList<L> {}
私は複数回のタイプを再利用避けるだろう、それはレベルを維持する方が簡単ですまっすぐ。 useList()メソッドは、実際にそれが内部的に両方のタイプを使用しているため、二重のパラメータ化を必要とします:
static <L extends List<T>,T extends Number>
Set<NumberLists<L,T>> useList(L list) {
NumberLists<L,T> nl = new NumberLists<L, T>();
nl.add(list);
return Collections.singleton(nl);
}
このフレームワークは、限り、あなたは具体的なクラスを持っているように素晴らしい作品:
// Everything works with a concrete class
List<Integer> intList = new ArrayList<Integer>();
// Use with parametric functions
Set<NumberLists<List<Integer>,Integer>> concreteSet = useList(intList);
// Access & use elements
NumberLists<List<Integer>,Integer> concreteNL = concreteSet.iterator().next();
concreteNL.add(intList);
問題はそのIであります
static List<? extends Number> makeList() {
if(Math.random()<.5) {
return new ArrayList<Integer>();
} else {
return new ArrayList<Double>();
}
}
List<? extends Number> numList = makeList();
これは、上記で可能な多くのパターンを壊します。
// What is the type here? This is obviously an error
Set<NumberLists<? extends List<? extends Number>>,? extends Number> paramSet = useList(numList);
// Type should ideally be compatible with numList still
NumberLists<?,?> paraNL1 = paramSet.iterator().next();
// Captures don't match
paraNL1.add(numList);
したがって、コンパイル時にnumListの具体的なクラスを知ることができないという問題があります。私はnumListの型がuseListによって返される型と一致しなければならないことを知っているので、実際に型が安全でないものは何もしていないように感じます。
私はコードのほとんどの部分の型署名を管理しています。しかし、私は次のことを好むだろう:
- 、また、型が実行時まで、具体的に知ることができない入力を受け取ることになります具象クラス(例えばintList)
- とうまくやタイプセーフな方法で動作するはずです
- キャストまたはその他のチェックされていない操作が実行されると、入力の構成の近くで発生するはずです。以下の操作をチェックする必要があります。
完全なコンパイル以外のJavaファイルについては、https://gist.github.com/sbliven/f7babb729e0b1bee8d2dabe5ee979431を参照してください。私がこの質問に興味がある理由は、https://github.com/biojava/biojava/issues/354を参照してください。
あなたのリストにはリストがあり、 'useList()' expectリストには 'List'ではなく' Number'が含まれています。 – markspace
@markspaceトップコードブロックでは、LにList <をバインドすることを望んでいました。 Number>を拡張します。私はそれがレベルの正しい数だと思う。 – Quantum7
質問を更新し、ネストされたリストの使用を避けました。うまくいけば、タイプシグネチャの混乱を少なくします。 – Quantum7