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>
タイプでもありArrayList<Integer>
ます。つまり、 で次のことができますmain
。
ArrayList<?> s = new ArrayList<String>();
f1.add(s);
ArrayList<?> i = new ArrayList<Integer>();
f1.add(i);
ここで、コンパイラが引数として呼び出すことgo()
を許可していると仮定しましょう。f1
推論するオプションは次のT
とおりです。
T = Object
ですが、は
So that is not allowed オプションと同じタイプでArrayList<ArrayList<Object>>
はないArrayList<ArrayList<?>>
ため、そうではありません。ArrayList<Object>
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) {
}