- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
原始列表转换为 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;
}
背景故事(缓解 the xy problem ):
我正在使用的 API 返回 List<JAXBElement>
.我碰巧知道它总是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 称为 unchecked conversion :
There is an unchecked conversion from the raw class or interface type (§4.8)
G
to any parameterized type of the formG<T<sub>1</sub>,...,T<sub>n</sub>>
.
具体来说,它是 assignment context 的特例仅适用于这种情况:
If, after [other possible conversions] have been applied, the resulting type is a raw type, an unchecked conversion may then be applied.
#2需要引用类型转换;然而问题在于它不是 widening conversion (这是一种在没有转换的情况下隐式允许的引用转换)。
这是为什么呢?好吧,这是由 rules of generic subtyping 专门管理的更具体地说,这个要点:
Given a generic type declaration
C<F<sub>1</sub>,...,F<sub>n</sub>>
(n > 0), the direct supertypes of the parameterized typeC<T<sub>1</sub>,...,T<sub>n</sub>>
, whereT<sub>i</sub>
(1 ≤ i ≤ n) is a type, are all of the following:
C<S<sub>1</sub>,...,S<sub>n</sub>>
, whereS<sub>i</sub>
containsT<sub>i</sub>
(1 ≤ i ≤ n).
这指的是 JLS 称为 containment 的东西,要成为有效的赋值,左侧的参数必须包含右侧的参数。自 "concrete" generic types 以来,遏制在很大程度上控制了通用子类型化是invariant .
您可能熟悉以下想法:
List<Dog>
不是 List<Animal>
List<Dog>
是 List<? extends Animal>
.嗯,后者是正确的,因为 ? extends Animal
包含 Dog
.
所以问题变成了“类型参数 List<?>
是否包含原始类型参数 List
”?答案是否定的:虽然 List<?>
是 List
的子类型,这种关系不适用于类型参数。
没有特殊规则使它成立:List<List<?>>
不是 List<List>
的子类型出于基本相同的原因List<Dog>
不是 List<Animal>
的子类型.
所以因为List<List>
不是 List<List<?>>
的子类型, 赋值无效。同样,您不能直接执行 narrowing conversion类型转换因为List<List>
不是 List<List<?>>
的父类(super class)型要么。
要进行分配,您仍然可以应用强制转换。有 3 种方法在我看来是合理的。
// 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>
更严格的类型.
原始类型 语句是一个扩大的转换然后是未经检查的赋值。这是可行的,因为如上所示,任何参数化类型都可以转换为其原始类型,反之亦然。
slightly safe 语句(之所以这样命名是因为它丢失的类型信息较少)是先扩大转换再缩小转换。这通过转换为通用父类(super class)型来实现:
List<? extends List>
╱ ╲
List<List<?>> List<List>
有界通配符允许类型参数被考虑用于通过包含进行子类型化。
事实List<? extends List>
被认为是 List<List<?>>
的父类(super class)型可以用传递性证明:
? extends List
包含 ? extends List<?>
,因为 List
是 List<?>
的父类(super class)型.
? extends List<?>
包含 List<?>
.
因此? extends List
包含 List<?>
.
(即 List<? extends List> :> List<? extends List<?>> :> List<List<?>>
。)
第三个示例的工作方式与第二个示例类似,转换为通用父类(super class)型 List<? super List<?>>
。 .由于它不使用原始类型,因此我们可以减少一个警告。
这里的非技术总结是规范暗示List<List>
之间既没有子类型也没有父类(super class)型关系。和 List<List<?>>
.
尽管从 List<List>
转换而来至 List<List<?>>
应该是安全的,这是不允许的。 (这是安全的,因为两者都是 List
,可以存储任何类型的 List
,但是 List<List<?>>
对其元素在检索后的使用方式施加了更多限制。)
不幸的是,除了原始类型很奇怪并且它们的使用存在问题之外,没有实际原因导致编译失败。
关于java - 无法从 List<List> 转换为 List<List<?>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52523554/
我想使用 R 预定义这样的列表 DATA<-list( list(list(),list(),list()), list(list(),list(),list()), list(list(),l
如何将一个列表添加到另一个列表,返回一个列表的列表? foo :: [a] -> [a] -> [[a]] 例如,我想要的结果是: foo [1,2] [3,4] 将是 [[1,2], [3,4]]。
我还没有在这里找到类似问题的解决方案,所以我会寻求你的帮助。 有 2 个列表,其中之一是列表列表: categories = ['APPLE', 'ORANGE', 'BANANA'] test_re
这个问题不同于Converting list of lists / nested lists to list of lists without nesting (这会产生一组非常具体的响应,但无法解决
原始列表转换为 List正好。为什么原始列表的列表不能转换为 List 的列表? { // works List raw = null; List wild = raw; } {
在下面的代码中,get()被调用并将其结果分配给类型为 List> 的变量. get()返回 List>并在类型参数为 T 的实例上调用设置为 ? ,所以它应该适合。 import java.util
原始列表转换为 List正好。为什么原始列表的列表不能转换为 List 的列表? { // works List raw = null; List wild = raw; } {
在insufficiently-polymorphic 作者说: def foo[A](fst: List[A], snd: List[A]): List[A] There are fewer way
我有下面的代码有效。 class ListManipulate(val list: List, val blockCount: Int) { val result: MutableList>
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 5 年前。 Improve this ques
在 scala (2.9) 中转换列表列表的最佳方法是什么? 我有一个 list : List[List[A]] 我想转换成 List[A] 如何递归地实现这一点?或者还有其他更好的办法吗? 最佳答案
我编写了这个函数来确定给定元素是否存储在元组列表的列表中,但目前它只搜索第一个列表。我将如何搜索其余列表? fun findItem (name : command, ((x,y)::firstlis
我创建了一个类名 objectA,它有 4 个变量:约会时间;字符串文本;变量 1,变量 2 我需要创建一个 ObjectA() 列表。然后首先按时间对它们进行分组,其次按 var1,然后按 var2
我有一套说法 char={'J','A'} 和列表的列表 content = [[1,'J', 2], [2, 'K', 3], [2, 'A', 3], [3,'A', 9], [5, 'J', 9
我有以下列表 List >>> titles = new ArrayList >>> ();我想访问它的元素,但我不知道该怎么做.. 该列表有 1 个元素,它又包含 3 个元素,这 3 个元素中的
转换 List[List[Long]] 的最佳方法是什么?到 List[List[Int]]在斯卡拉? 例如,给定以下类型列表 List[List[Long]] val l: List[List[Lo
我有一个来自 Filereader (String) 的 List-List,如何将其转换为 List-List (Double):我必须返回一个包含 line-Array 的第一个 Values 的
我收集了List> 。我需要将其转换为List> 。这是我尝试过的, List> dataOne = GetDataOne(); var dataTwo = dataOne.Select(x => x
这个问题在这里已经有了答案: Cannot convert from List to List> (3 个答案) 关闭 7 年前。 我没有得到这段代码以任何方式编译: List a = new Ar
这个问题在这里已经有了答案: Cannot convert from List to List> (3 个答案) 关闭 7 年前。 我没有得到这段代码以任何方式编译: List a = new Ar
我是一名优秀的程序员,十分优秀!