gpt4 book ai didi

java - 泛型的泛型和更通用的 赋值

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:45:34 24 4
gpt4 key购买 nike

有时我就是不懂泛型。我经常在代码中使用最通用的集合版本。例如,如果我需要一组任何东西,我会写这样的东西:

Set<?> set1 = new HashSet<Object>();

它是编译器允许的,为什么不应该 - Set<?>Set<Object>一样一般(或者更通用......)。但是,如果我使用“generics of generics”使其“更通用”是行不通的:

Set<Class<?>> singletonSet = new HashSet<Class<Object>>(); // type mismatch

这是怎么回事?为什么是Set<Object>可分配给 Set<?>Set<Class<Object>>不可分配给 Set<Class<?>>


我总能找到解决此类问题的方法,但在这种情况下,我真的很想知道为什么不允许这样做并且不是解决方法。

最佳答案

鉴于此:

Set<?> set1 = new HashSet<Great>();

如果您形象化无限通配符的含义,这将起作用,将无限通配符上的开槽类型与 extends 进行比较,所以如果你明确地这样做。

Set<? extends Object> set1 = new HashSet<Great>();

阅读,是Great extending Object吗?是的,这样就可以编译了。

然后给出这个:

Set<Class<Great>> set3 = new HashSet<Class<Great>>();

为什么它有效,如果你提取 Set 和 HashSet 的参数,它们是 Class<Great> , 那两个 Class<Great>是完全相同的类型。

没有通配符的情况下,直接逐字比较类型。

如果我们编写 set3 使其接受协变类型(这会编译):

Set<? extends Class<Great>> set3a = new HashSet<Class<Great>>();

读取,就是HashSet的Class<Great>与 Set 的 Class<Great> 类型兼容或协变?是的。因此它编译。<​​/p>

虽然如果它们只是完全相同的类型,当然没有人会写那种变量声明,但这是多余的。编译器使用通配符来确定赋值右侧的泛型具体类或接口(interface)参数是否与左侧泛型的具体/接口(interface)(理想接口(interface),如下所示)兼容。

List<? extends Set<Great>> b = new ArrayList<HashSet<Great>>();

阅读它,是HashSet<Great>Set<Great> 协变?是的。因此它编译


那么让我们回到您的代码场景:

Set<Class<?>> set3 = new HashSet<Class<Object>>();

在这种情况下,同样的规则适用,你从最里面开始读,Object兼容通配符吗?是的。然后你去下一个最外层的类型,它恰好没有通配符。所以在没有通配符的情况下,编译器将在 Class<Object> 之间进行逐字检查。和 Class<?> , 它们不相等,因此会出现编译错误。

如果它在最外层有通配符,那将编译。所以你的意思可能是,编译:

Set<? extends Class<?>> singletonSet = new HashSet<Class<Object>>();

让我们做一个更有启发性的例子,让我们使用接口(interface)(类是具体类型),比如 Set。这编译:

List<? extends Set<?>> b = new ArrayList<HashSet<Object>>();

所以从里到外阅读它以找出代码编译的原因,并明确地执行它:

  1. 最里面:是 Object兼容 ? Extends Object ?当然是。

  2. 最外层:是 HashSet<Object>兼容 ? extends Set<? extends Object> ?肯定是。

在数字 1 上,是这样的(编译):

Set<? extends Object> hmm = new HashSet<Object>();

在数字 2 上,是这样的(编译):

List<? extends Set<? extends Object>> b = new ArrayList<HashSet<Object>>();

现在让我们尝试删除最外面的通配符,编译器将不会进行类型兼容/协变检查,现在将逐字比较。

所以你现在知道以下问题的答案了,这些可以编译吗?

List<Set<?>> b = new ArrayList<HashSet<Object>>();

// this is same as above:
List<Set<? extends Object>> b = new ArrayList<HashSet<Object>>();

所以你已经猜到了,正确的......不会编译:-)

要更正上述问题,请执行以下任一操作:

List<? extends Set<? extends Object>> b = new ArrayList<HashSet<Object>>();

List<? extends Set<?>> b = new ArrayList<HashSet<Object>>();

然后,要更正您的代码,请执行以下任一操作:

Set<? extends Class<? extends Object>> singletonSet = 
new HashSet<Class<Object>>();

Set<? extends Class<?>> singletonSet = new HashSet<Class<Object>>();

关于java - 泛型的泛型和更通用的 <?> 赋值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10752303/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com