Java wildcard in multi

Why Bar.go is OK with argument f2 but not with argument f1 ?

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) {
    }
}

Shouldn't the compiler automatically infer type T as capture of ? in both cases?


Great question!

(In the following comments, wrt a class generic in E like Foo< E > , define "covariant method" as a method that returns an E without having any parameters using E , and a "contravariant method" as the opposite: one which takes a formal parameter of type E but doesn't return a type involving E . [The real definition of these terms is more complicated, but never mind that for now.])

It seems that the compiler is trying to bind T to Object in the case of f1 , because if you do

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
    }
}

then the go(f1) works, but now go(f2) doesn't, because even though Foo< String > <: Foo< ? extends String > Foo< String > <: Foo< ? extends String > , that does not imply that Foo< Foo< String > > <: Foo< Foo< ? extends String > > Foo< Foo< String > > <: Foo< Foo< ? extends String > > .

Here are a few modifications that compile for both f1 and 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
    }
}

Foo<Foo<?>> f1 = new Foo<Foo<?>>();

This implies that the type is unknown and objects of any type can be added to Foo<Foo<?>> that are heterogeneous and compiler cannot guarantee that all object in Foo<Foo<?>> are of same type. Hence it cannot be passed to Bar.go that takes a bounded type as parameter.

You can instead declare that as Foo<Foo<Object>> f1 = new Foo<Foo<Object>>(); to pass it to Bar.go where you explicitly mention everything is of type Object .


A Nice Read What do multi-level wildcards mean?

Example:

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  

Of course, we can assign a Collection<Pair<String,Long>> to a Collection<Pair<String,Long>> . There is nothing surprising here.

But we can not assign a Collection<Pair<String,Long>> to a Collection<Pair<String,?>> . The parameterized type Collection<Pair<String,Long>> is a homogenous collection of pairs of a String and a Long ; the parameterized type Collection<Pair<String,?>> is a heterogenous collection of pairs of a String and something of unknown type. The heterogenous Collection<Pair<String,?>> could for instance contain a Pair<String,Date> and that clearly does not belong into a Collection<Pair<String,Long>> . For this reason the assignment is not permitted.

链接地址: http://www.djcxy.com/p/63998.html

上一篇: 任何等效的“扩展”的C#?

下一篇: 多通用Java通配符