我在理解以下两个方法签名之间的差异时遇到问题。
abstract class Example {
void test() {
Class<? extends Parent<? extends Child>> clazz = null;
works(clazz);
error(clazz); // Error
}
abstract <T extends Child> Parent<T> works(Class<? extends Parent<? extends T>> clazz); // Method1
abstract <T extends Child> Parent<T> error(Class<? extends Parent<T>> clazz); // Method2
interface Child {}
interface Parent<U extends Child> {}
}
Run Code Online (Sandbox Code Playgroud)
编译此代码会出现以下错误(使用 1.8.0_271、11.0.9 和 15.0.1 测试)。
…/src/main/java/Example.java:6:5
java: method error in class Example cannot be applied to given types;
required: java.lang.Class<? extends Example.Parent<T>>
found: java.lang.Class<capture#1 of ? extends Example.Parent<? extends Example.Child>>
reason: cannot infer type-variable(s) T
(argument mismatch; java.lang.Class<capture#1 of ? extends Example.Parent<? extends Example.Child>> cannot be converted to java.lang.Class<? extends Example.Parent<T>>)
Run Code Online (Sandbox Code Playgroud)
为什么? extends需要?T 已经在类型参数 ( T extends Child) 中扩展了 Child ,这个额外的东西? extends对我来说似乎是多余的。
更新:
使用 javac 开始-DverboseResolution=all更具描述性但仍然令人困惑
…src/main/java/Example.java:6: error: method error in class Example cannot be applied to given types;
error(clazz); // Error
^
required: Class<? extends Parent<T>>
found: Class<CAP#1>
reason: cannot infer type-variable(s) T
(argument mismatch; Class<CAP#1> cannot be converted to Class<? extends Parent<T>>)
where T is a type-variable:
T extends Child declared in method <T>error(Class<? extends Parent<T>>)
where CAP#1 is a fresh type-variable:
CAP#1 extends Parent<? extends Child> from capture of ? extends Parent<? extends Child>
Run Code Online (Sandbox Code Playgroud)
解释这个:
必需的是Class<? extends Parent<T>>。T是extends Child。所以让我们把它放在一起Class<? extends Parent<? extends Child>>。
发现是Class<CAP#1>。CAP#1是extends Parent<? extends Child>。这一起给了我Class<? extends Parent<? extends Child>>
所以两个签名是一样的?!?
更新:
在 Eclipse 中编译此代码有效。与 javac 相比,Eclipse 编译器将签名视为相同。
该类型Class<Parent<? extends Child>>可以传递给第一个签名,但不能传递给第二个签名,并且由于Class<Parent<? extends Child>>可以分配给 a Class<? extends Parent<? extends Child>>,因此Class<? extends Parent<? extends Child>>也不能传递给第二个签名。
所以问题就归结为为什么Class<Parent<? extends Child>>不能传递给第二个签名(<T extends Child> Parent<T> error(Class<? extends Parent<T>> clazz))。我们可以看到,这是因为无论您选择哪种特定类型,都Parent<? extends Child>不能是 的子类型。(是 的子类型,但反之则不然。)Parent<T>TParent<T>Parent<? extends Child>
List<Parent<? extends Child>>考虑为什么不能传递给 的签名的等效问题<T extends Child> Parent<T> error(List<? extends Parent<T>> clazz)。A允许您同时List<Parent<? extends Child>>将Parent<ChildA>和元素添加到同一个列表中。Parent<ChildB>换句话说,它是一个“异构列表”。另一方面,对于 的任何给定选择T,a List<Parent<T>>(或List<SubclassOfParent<T>>)是一个只能包含Parent单一类型参数的对象的列表。这是一个“同质列表”。即使泛型允许您一般地对各种类型参数的同质列表进行操作,同质列表仍然与异质列表不同。两者是不相容的。
| 归档时间: |
|
| 查看次数: |
121 次 |
| 最近记录: |