据我了解,<? 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
}
}
有人可以帮助我理解这种行为。
答案 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