私は、コンパイラがBar.go(f1);
を許可する場合、型システム(安全性)が壊れてしまうことを証明します:
Javaの文法を変数を宣言する型としてT
をgo()
に使用することができます。何かのように:T t = <something>
。
さて、ArrayList
代わりのFoo
を使用してみましょう、
その後、我々が持っている:
class HW {
public static void main(String[] args) {
ArrayList<ArrayList<?>> f1 = new ArrayList<ArrayList<?>>();
go(f1); // not OK
}
public static <T> void go(ArrayList<ArrayList<T>> f) {
}
}
ArrayList<?>
はArrayList<String>
のスーパータイプである、それはあなたがmain
で次の操作を行うことができることを意味し、またArrayList<Integer>
のスーパータイプであります:
ArrayList<?> s = new ArrayList<String>();
f1.add(s);
ArrayList<?> i = new ArrayList<Integer>();
f1.add(i);
次に、コンパイラではf1
を引数としてgo()
を呼び出すことができます。 T
を推測するためのオプションがあります:ArrayList<Object>
はArrayList<?>
だからそれが許可されていないオプションと同じタイプではないので
T = Object
が、ArrayList<ArrayList<Object>>
がArrayList<ArrayList<?>>
ではありません。
T = ?
、そして我々が行うことができるだろう:
public static <T> void go(ArrayList<ArrayList<T>> f) {
ArrayList<T> alt1 = f.get(0); // ArrayList<String>
T str = alt1.get(0);
ArrayList<T> alt2 = f.get(1); // ArrayList<Integer>
alt2.add(str); // We have added String to List<Integer>
// ... type system broken
}
go()
あなたがしなければならない両方のケースで動作するように:
public static void go(ArrayList<? extends ArrayList<?>> f) {
}
作業の例を見るのは素晴らしいことです。 – Cyker
'Foo>'の場合はどうですか?私が 'Foo >'という言い方で作業する必要があるなら、 'Foo <? 'と書くことができます。 extends Foo >> '' Foo > 'を使うことができれば、私が実際に意図するより多くの分散をもたらすと感じます。どのように 'Foo 'を 'Foo >'として受け入れるかは、分散の観点からどのように呼び出されますか? –
ony
私はあなたの質問を理解していれば、それは全く受け入れられません。 'Foo>'は 'Foo < Foo< ? >>'ではありません。一般的に 'G < S >'は 'S'が 'T 'であっても' G < T >'ではありませんが 'G < S >'は 'G <? 'G'は' G < ? super S > 'です。 'Foo < ? >'は 'Foo <? extends Object> 'なので、' Foo < String > 'は' Foo < ? > 'です。しかし、 'Foo < String >'を 'S'、' Foo < ? > 'を' T'とします。上記の関係がないと、 'Foo < S >'は 'Foo < T >'ではありません。 –