多通用Java通配符

为什么Bar.go OK使用参数f2但不使用参数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) {
    }
}

编译器是否应该自动推断类型Tcapture of ? 在这两种情况下?


伟大的问题!

(在下面的注释中,像Foo< E >那样在E有一个泛型类,将“协变方法”定义为返回E而不使用E任何参数的方法,以及“逆变法”作为相反的方法: E类型的形式参数,但不返回涉及E的类型[这些术语的真正定义比较复杂,但现在不用介意])

看起来,编译器正试图在f1的情况下将T绑定到Object ,因为如果你这样做的话

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< String > <: Foo< ? extends String > ,这并不意味着Foo< Foo< String > > <: Foo< Foo< ? extends String > > Foo< Foo< String > > <: Foo< Foo< ? extends String > >

以下是针对f1f2编译的一些修改:

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<?>>();

这意味着该类型是未知的,并且任何类型的对象都可以被添加到异构的Foo<Foo<?>> ,并且编译器不能保证Foo<Foo<?>>中的所有对象都是相同类型的。 因此它不能传递给Bar.go ,它将一个有界类型作为参数。

你可以改为声明为Foo<Foo<Object>> f1 = new Foo<Foo<Object>>(); 将其传递给Bar.go ,您明确提到所有内容都是Object类型的。


很好的阅读什么是多级通配符?

例:

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,?>>是String和某些未知类型对的异构集合。 异构Collection<Pair<String,?>>可以包含一个Pair<String,Date> ,并且显然不属于Collection<Pair<String,Long>> 。 出于这个原因,分配是不允许的。

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

上一篇: Java wildcard in multi

下一篇: Prolog Binary Addition Issue?