7

with argument なのに with argumentではないのBar.goはなぜですか?OKf2f1

public class HelloWorld {
    public static void main(String[] args) {
        Foo<Foo<?>> f1 = new Foo<Foo<?>>();
        Foo<Foo<String>> f2 = new Foo<Foo<String>>();
        Bar.go(f1);     // not OK
        Bar.go(f2);     // OK
    }

    public static void p(Object o) {
        System.out.println(o);
    }
}

class Foo<E> {
}

class Bar {
    public static <T> void go(Foo<Foo<T>> f) {
    }
}

どちらの場合も、コンパイラは自動的に型Tを推測すべきではありませんか?capture of ?

4

4 に答える 4

2

素晴らしい質問です!

E(以下のコメントでは、のようにジェネリッククラスを作成し、「共変メソッド」を、を使用してパラメーターを持たずにFoo< E >返すメソッドとして定義し、「反変メソッド」をその反対として定義します。を含む型を返さないでください。[これらの用語の実際の定義はより複雑ですが、今のところ気にしないでください。])EEEE

の場合、コンパイラはバインドしようとしてTいるようです。Objectf1

class Bar0 {
    public static < T > void go( Foo< Foo< ? extends T > > f ) {
        // can pass a Foo< T > to a contravariant method of f;
        // can use any result r of any covariant method of f,
        // but can't pass T to any contravariant method of r
    }
}

その後はgo(f1)機能しますが、現在go(f2)は機能しません。なぜならFoo< String > <: Foo< ? extends String >、それはそれを意味するものではないからFoo< Foo< String > > <: Foo< Foo< ? extends String > >です。

f1との両方をコンパイルするいくつかの変更を次に示しますf2

class Bar1 {
    public static < T > void go( Foo< ? super Foo< T > > f ) {
        // can't properly type the results of any covariant method of f,
        // but we can pass a Foo< T > to any contravariant method of f
    }
}

class Bar2 {
    public static < T > void go( Foo< ? extends Foo< ? extends T > > f ) {
        // can't pass a Foo< T > to a contravariant method of f;
        // can use result r of any covariant method of f;
        // can't pass a T to a contravariant method of r;
        // can use result of covariant method of r
    }
}
于 2012-09-23T05:12:52.587 に答える
2
Foo<Foo<?>> f1 = new Foo<Foo<?>>();

これは、型が不明であり、Foo<Foo<?>>異種の任意の型のオブジェクトを追加できることを意味し、コンパイラは、のすべてのオブジェクトFoo<Foo<?>>が同じ型であることを保証できません。Bar.goしたがって、パラメータとして有界型をとるに渡すことはできません。

代わりに、すべてがタイプであることを明示的に言及Foo<Foo<Object>> f1 = new Foo<Foo<Object>>();する場所に渡すように宣言することができます。Bar.goObject

于 2012-09-23T03:39:46.770 に答える
0

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とおりです。

  1. T = Objectですが、は So that is not allowed オプションと同じタイプでArrayList<ArrayList<Object>>はないArrayList<ArrayList<?>>ため、そうではありません。ArrayList<Object>ArrayList<?>

  2. 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) {
}
于 2012-09-23T06:29:27.167 に答える
0

参考資料 マルチレベルのワイルドカードとは?

例:

Collection< Pair<String,Long> >        c1 = new ArrayList<Pair<String,Long>>();

Collection< Pair<String,Long> >        c2 = c1;  // fine
Collection< Pair<String,?> >           c3 = c1;  // error
Collection< ? extends Pair<String,?> > c4 = c1; // fine  

もちろん、 を に代入できCollection<Pair<String,Long>>ますCollection<Pair<String,Long>>。ここで驚くべきことは何もありません。

しかし、 を に代入することはできませCollection<Pair<String,Long>>Collection<Pair<String,?>>。パラメータ化された型Collection<Pair<String,Long>>は、 String と Long のペアの同種のコレクションです。パラメータ化された型Collection<Pair<String,?>>は、文字列と不明な型のペアの異種コレクションです。異質なものにCollection<Pair<String,?>>は、たとえば aPair<String,Date>を含むことができ、それは明らかに a に属しませんCollection<Pair<String,Long>>。このため譲渡は認められません。

于 2012-09-23T03:45:25.820 に答える