原始列表将转换为List<?>
正常。为什么原始列表的列表不能转换为的列表List<?>
?
{ // works
List raw = null;
List<?> wild = raw;
}
{ // Type mismatch: cannot convert from List<List> to List<List<?>>
List<List> raw = null;
List<List<?>> wild = raw;
}
背景故事(以减轻xy问题):
我正在使用return的API List
List<JAXBElement<String>>
。我计划循环并构建自己的循环
List<String>
,但是我在尝试编写时试图修复(但不禁止)原始类型编译器警告
List<JAXBElement> raw = api()
;。
我试过了:
List<JAXBElement<?>> raw = api();
List<JAXBElement<?>> raw = (List<JAXBElement<?>>) api();
但是这些会导致类型不匹配错误。
有趣的是,这没有给出警告或错误:
for (JAXBElement<?> e : api()) {
// ...
}
// #1 (does compile)
List raw = null;
List<?> wild = raw;
// #2 (doesn't compile)
List<List> raw = null;
List<List<?>> wild = raw;
首先让我们弄清楚为什么这些实际上是不相关的分配。也就是说,它们受不同规则的约束。
#1称为未经检查的转换:
存在未检查的转换从原始类或接口类型(§4.8)G的任何参数化的类型的形式的。G<T1,...,Tn>
具体地说,这是仅在此情况下分配上下文的一种特殊情况:
如果在应用了[其他可能的转换]之后,结果类型为原始类型,则可以应用未经检查的转换。
#2需要引用类型转换;但是,问题在于它不是扩展转换(这是一种无需转换就可以隐式允许的引用转换)。
这是为什么?好吧,这特别受通用子类型化规则的支配,更具体地讲,要点如下:
给出一个通用的类型声明(Ñ > 0),则直接超参数化类型的,其中,(1≤我≤ Ñ)是一种类型的,是以下所有:C<F1,...,Fn>C<T1,...,Tn>Ti
C<S1,...,Sn>
,其中包含(1≤我≤ Ñ)。SiTi
这就是JLS所称的containment,这是有效的赋值,左侧的参数必须包含右侧的参数。由于“具体”泛型类型是不变的,因此包含在很大程度上决定了泛型子类型。
您可能熟悉以下想法:
一个List<Dog>
不是一个List<Animal>
但是aList<Dog>
是一个List<? extends Animal>
。
好吧,后者是正确的,因为? extends Animal contains Dog
。
因此问题变成“类型参数是否List<?>
包含原始类型参数List”?答案是否定的:尽管List<?>
是的子类型List,但此关系不适用于类型实参。
没有特殊的规则可以实现:List<List<?>>
不是的子类型,List<List>
从本质List<Dog>
上讲,不是的子类型List<Animal>
。
因此,由于List<List>
不是的子类型List<List<?>>
,因此分配无效。同样,您不能执行直接缩小转换强制转换,因为它既不是二者List<List>
的超类List<List<?>>
。
要进行分配,您仍然可以应用强制转换。在我看来,有三种方法可以做到。
// 1. raw type
@SuppressWarnings("unchecked")
List<List<?>> list0 = (List) api();
// 2. slightly safer
@SuppressWarnings({"unchecked", "rawtypes"})
List<List<?>> list1 = (List<List<?>>) (List<? extends List>) api();
// 3. avoids a raw type warning
@SuppressWarnings("unchecked")
List<List<?>> list2 = (List<List<?>>) (List<? super List<?>>) api();
(您可以替换JAXBElement内部List。)
此类型转换的用例应该是安全的,因为List<List<?>>
它比更具限制性List<List>
。
该原始类型语句是拓宽投选中,然后分配。之所以可行,是因为如上所述,任何html" target="_blank">参数化类型都可以转换为其原始类型,反之亦然。
在稍微安全的声明(如此命名是因为它失去了较少类型信息)是拓宽投则投缩小。这通过强制转换为普通的超类型来工作:
List<? extends List>
╱ ╲
List<List<?>> List<List>
有界通配符允许将类型参数考虑为通过包含进行子类型化。
List<? extends List>
被认为是超类的事实List<List<?>>
可以通过传递性来证明:
? extends List
包含?extends List<?>
,因为List是的超类型List<?>
。
? extends List<?>
包含List<?>
。
因此? extends List包含List<?>
。
(即List<? extends List> :> List<? extends List<?>> :> List<List<?>>。)
第三个示例的工作方式与第二个示例类似,通过强制转换为公共超类型List<? super List<?>>
。由于它不使用原始类型,因此我们可以减少一个警告。
这里的非技术性总结是,规范意味着有间既不亚型也不超关系List<List>
和List<List<?>>
。
虽然从转换List<List>
到List<List<?>>
应该是安全的,这是不允许的。(这是安全的,因为两者都是List
可以存储任何类型的List,但是List<List<?>>
对检索元素后如何使用它施加了更多限制。)
不幸的是,除了原始类型是奇怪的而且它们的使用有问题之外,没有任何实际原因无法编译。
我在我的项目中使用spring webflux与外部API进行通信。在我的项目中,我无法将Flux转换为List。 在尝试对collectList().block()执行同样的操作时,flux的所有元素都被连接到一个字符串中,并存储在List的第0个索引处。如果我返回Flux而不是List,那么它会发送预期的响应。但我需要操作内容并将其作为子对象添加到其他对象中&因此尝试返回列表。 预期结果:[“
我有一个方法createCompliance响应(),它返回BOLConplationObject对象,在此之前,我将其更改为BOLConplationMono,因为我必须在其中调用另一个反应性服务。但是在这样做之后,我调用该服务的当前服务在第6行和第7行出现错误。 我为其更改了退货类型的另一项服务是
ProjectConfigurationException:配置项目“:App”时出现问题。在org.gradle.configuration.project.lifecycleProjectEvaluator.addConfigurationFailure(lifecycleProjectEvaluator.java:94)在org.gradle.configuration.project.li
我有一个以下格式的日期,我需要解析它,并转换成一个纪元时间。 关于我做错了什么有什么帮助吗?
当我这样做的时候 如何解析datetime字符串,以便将其解释为始终来自时区“欧洲/柏林”?
问题内容: 这是我第一次尝试使用ui-router。 这是我的app.js 如您所见,我有两种状态。我正在尝试这样注册状态: 但是我越来越 无法从状态“解析”“注册” 例外。这里有什么问题? 问题答案: 这种错误通常表示(JS)代码的某些部分未加载。里面的状态不见了。 有一个可行的例子 我不是离子技术方面的专家,因此此示例应表明它可以正常工作,但我使用了更多技巧(用于制表符的父级) 这是一个调整后