繁体   English   中英

具有冗余类型参数的通用方法

[英]Generic method with redundant type parameter

我无法理解以下两个方法签名之间的差异。

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

编译此代码会出现以下错误(使用 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>>)

为什么是? extends 需要? extends吗? T 已经在类型参数中扩展了 Child ( T extends Child ) 并且这个附加的? extends ? extends对我来说似乎是多余的。


更新:

使用-DverboseResolution=all启动 javac 更具描述性,但仍然令人困惑

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

解释这个:

要求是Class<? extends Parent<T>> Class<? extends Parent<T>> Textends Child 所以让我们把它放在Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>>

找到的是Class<CAP#1> CAP#1extends Parent<? extends Child> extends Parent<? extends Child> 这一起给了我Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>>

所以两个签名是一样的???


更新:

在 Eclipse 中编译此代码有效。 与 javac 相比,Eclipse 编译器将签名视为相同。

我也为自己做了很长的解释, 在这里 如果你想读它。 加上这与捕获转换有关。

简而言之,在您的情况下,编译器根本无法证明通配符捕获与T兼容。 如果您使用: javac --debug=verboseResolution=all...运行,您将看到如下错误:

....
(argument mismatch; Class<CAP#1> cannot be converted to Class<? extends Parent<T>>)

所以捕获转换CAP#1 )不能简单地满足这里的编译器。 使其工作的方法是通过...<? extends T> ...<? extends T> 这可以通过编译器证明? extends Child ? extends Child is <: (第二个链接中解释的符号) ? extends T ? extends T ; 因此协方差成立。

也有人说“有界通配符使类型协变”。

类型Class<Parent<? extends Child>> Class<Parent<? extends Child>>可以传递给第一个签名,而不能传递给第二个签名,并且由于Class<Parent<? extends Child>> Class<Parent<? extends Child>>可以分配给一个Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>> ,它遵循Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>> Class<? extends Parent<? extends Child>>也不能传递给第二个签名。

所以问题归结为为什么Class<Parent<? extends Child>> Class<Parent<? extends Child>>不能传递给第二个签名( <T extends Child> Parent<T> error(Class<? extends Parent<T>> clazz) )。 我们可以看到那是因为Parent<? extends Child> Parent<? extends Child>不能是Parent<T>的子类型,无论您为T选择什么特定类型。 Parent<T>Parent<? extends Child>的子类型,但反之则不然。)

考虑一下为什么List<Parent<? extends Child>> List<Parent<? extends Child>>不能传递给<T extends Child> Parent<T> error(List<? extends Parent<T>> clazz)的签名。 一个List<Parent<? extends Child>> List<Parent<? extends Child>>允许您同时将Parent<ChildA>Parent<ChildB>元素添加到同一个列表中。 换句话说,它是一个“异构列表”。 另一方面,对于任何给定的T选择, List<Parent<T>> (或List<SubclassOfParent<T>> )是一个只能包含单个类型参数的Parent对象的列表。 这是一个“同质列表”。 即使 generics 通常允许您对各种类型的同构列表 arguments 进行操作,同构列表仍然是与异构列表不同的野兽。 两者不相容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM