Java 泛型好奇心
我有一个接口 A
,由类 B
实现。
以下通用方法有效,
public static <T, U extends T> List<T> listFactory(Collection<U> source) {
return new ArrayList<T>(source);
}
但
public static <T> List<T> listFactory(Collection<? extends T> source) {
return new ArrayList<T>(source);
}
不起作用(编译错误,类型不匹配),
List<A> tester = listFactory(B.defaultCollectionFactory(3));
当我将输出定向到defaultCollectionFactory(int count)
静态提供 B
的集合时, 使用默认的标签方案。
关于为什么会这样的任何见解吗?看起来通用 U 和通配符正在做同样的事情。
I have an interface A
, which class B
implements.
The following generic method works
public static <T, U extends T> List<T> listFactory(Collection<U> source) {
return new ArrayList<T>(source);
}
but
public static <T> List<T> listFactory(Collection<? extends T> source) {
return new ArrayList<T>(source);
}
does not (compilation error, type mismatch), when I am directing the output into
List<A> tester = listFactory(B.defaultCollectionFactory(3));
defaultCollectionFactory(int count)
statically provides a collection of B
s, with a default labeling scheme.
Any insights as to why that is? It seems like the generic U and wildcard are doing the same thing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编译器为
listFactory
方法推断出与您预期不同的类型参数。它推断T
是类型B
,因此签名实际上是List listFactory(Collectionsource)
。通过在方法调用中显式指定类型参数A
:The compiler is inferring a different type parameter for the
listFactory
method than you expect. It infers thatT
is typeB
, so the signature is effectivelyList<B> listFactory(Collection<? extends B> source)
. Specify the type parameterA
by being explicit in the method invocation:在第一个构造中,您指定要返回传入项目的接口的
List
。您在中指定传入的 Object 和返回的 Object 类型之间的关系。 >U 延伸 T
方向。在这种情况下,编译器可以将A
和B
分别与T
和U
关联起来。在第二种情况下,没有这样的区别,因此编译器假设
T
引用B
并将返回值键入为List
>。然后您就会陷入陷阱,尽管B
是A
的实例,但List
不是List< 的实例;A>
。编译器会抱怨:您会发现,使用第一个构造,您可以自由指定
B
实现的任何接口或B
中的任何超类的List
> 层次结构(例如List
In the first construct, you are specifying that you are returning a
List
of the interface of the item that was passed in. You specify the relationship between the passed in Object and the return Object type in theU extends T
direction. In this case, the compiler can associateA
andB
withT
andU
respectively.In the second, there is no such differentiation, so the compiler assumes that
T
refers toB
and will type the return value asList<B>
. You then fall into the trap where, althoughB
is an instance ofA
,List<B>
is not an instance ofList<A>
. The compiler will complain:You will find that, with the first construct, you have the liberty of specifying a
List
of any interface theB
implements or any superclass in theB
hierarchy (List<Object>
, for example), and the compiler will not complain.