通用符号<! - ? - >和&lt; ? extends Object&gt;行为不同

时间:2017-07-10 03:55:37

标签: java generics

据我了解,<? extends Object><?>是相同的。

但是,当我运行以下代码<? extends Object>时,不会编译并且按预期工作,但<?>已成功编译。

public class Test1 
{
    interface I1 
    {
    }

    interface I2<T extends I1> extends Comparable<I2<?>> 
    {
        Comparator<I2<? extends I1>> A = null;
        //Comparator<I2<? extends Object>> B = A; // expected compilation fail
        Comparator<I2<?>> B = A; // compiling successfully.This shouldn't get compile
    }
}

有人可以帮助我理解这种行为。

2 个答案:

答案 0 :(得分:7)

这个问题实际上很有意思,但没有明确提出,这很容易让人觉得它是重复的。

首先,我认为这里的大多数人应该理解为什么它不起作用的例子:

class Foo<T> {}
class Bar<T> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        Foo<Bar<? extends Object>> b = a;  // does not compile
        Foo<Bar<?>> c = a;                 // does not compile
    }
}

很明显:Foo<Bar<?>> / Foo<Bar<? extends Object>>无法转换为Foo<Bar<? extends Parent>>(简单地说:就像您无法将List<Dog>分配给List<Animal>引用一样。 )

但是,在这个问题中你可以看到Comparator<I2<?>> B = A;的情况确实编译了,这与我们上面看到的相矛盾。

我的例子中指出的区别是:

class Foo<T> {}
class Bar<T extends Parent> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        Foo<Bar<? extends Object>> b = a;  // does not compile
        Foo<Bar<?>> c = a;                 // COMPILE!!
    }
}

class Bar<T>更改为class Bar<T extends Parent>创建了差异。遗憾的是我仍然找不到对此负责的JLS部分,但是我相信当你在类型参数中声明一个带有bound的泛型类时,绑定被隐式地带到你使用的任何通配符上。

因此,该示例变为:

class Foo<T> {}
class Bar<T extends Parent> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        //...
        Foo<Bar<? extends Parent>> c = a;
    }
}

解释了为什么这个编译。

(对不起,我找不到证据,这就是语言的设计方式。如果有人能在JLS中找到这个,那将会很棒)

答案 1 :(得分:2)

让我用一个简单的例子向您解释:

List<String> list = new ArrayList<>();
List<Object> listObject = new ArrayList<>();
listObject = list;

这里,Object类是String类的超级类,但是你会收到以下指定的编译错误,因为你已经指定了你的列表只接受特定类型的对象,即'对象' listObject和'{1}}的字符串。

list

在下面的类似解释中,

Type mismatch: cannot convert from List<String> to List<Object>

上述行失败了,因为您试图对两种不匹配的类型进行类型转换:

//Comparator<I2<? extends Object>> B = A; // expected compilation fail