Java泛型:无法将List转换为List?
Java泛型中无法将List
假设以下代码是允许的:
Lista1 = new ArrayList (); List b1 = a1; // 假设这是允许的
那么我可以继续执行以下操作:
b1.add(new TreeThatIsntADataNode()); // b1是List,所以这是可以的 for (DataNode dn : a1) { // 啊哦!a1中有一些不是DataNode的东西! }
这样就会导致在遍历a1时出现类型不匹配的情况,违反了泛型的类型安全性。
在理想情况下,当使用只读的变体(variant)的List时,应该允许进行所需的类型转换,但是不允许在使用可读写的接口(如List)时进行类型转换。然而,Java不允许在泛型参数上使用这种variance的注解。即使允许使用,也只能在A和B完全相同的情况下将List转换为List。
虽然Java不允许在类的定义中使用此种variance的注解,但是可以使用通配符解决这个问题。可以将变量声明为List extends Tree>类型,这是允许的。
Java泛型不允许将List
问题的原因是Java中的泛型不支持将List
在上述代码中,我们有一个List
为了解决这个问题,我们可以使用通配符和双重转型。首先,我们将a1转换为一个通配符类型的列表,即List extends Tree>,这样就可以将a1赋值给该列表。然后,我们再将该列表强制转型为List
下面是解决这个问题的代码示例:
Lista1 = new ArrayList (); List b1 = (List ) (List extends Tree>) a1;
请注意,这种双重转型的方式是一种不太优雅的方式,因为它绕过了Java泛型的类型检查机制。在进行这种转型时,我们需要确保转换是安全的,即确保a1中的元素类型是Tree或其子类。否则,可能会导致运行时异常。
总之,泛型的不可协变性导致无法直接将List
Java泛型:无法将List
在第二种情况中,你看到的是数组协变。在我的观点中,这是一件不好的事情,它使得数组内的赋值是不安全的-尽管在编译时是正常的,但在执行时可能会失败。
在第一种情况中,想象一下,如果代码编译成功,并且接下来是这样的代码:
b1.add(new SomeOtherTree());
DataNode node = a1.get(0);
你会期望会发生什么呢?
你可以这样做:
List
List extends Tree> b1 = a1;
因为你只能从b1中获取东西,并且它们保证与Tree兼容。你不能调用b1.add(...),因为编译器无法确定它是否安全。
可以参考Angelika Langer的Java泛型FAQ中的这一部分,获取更多信息。
ah..! 这个是有效的:List extends Tree>
谢谢解释。你能给出一个“在数组内部不安全-尽管在编译时是正常的,但在执行时可能会失败”的例子吗?--忽略它。我找到了例子。
SoNG: 是的,基本上做与我的“错误”例子相同的事情,只是在数组中设置一个值而已 🙂
我遇到了类似的情况,经过了很多搜索之后,我打算发布一个新问题,但是碰巧遇到了这个。我尝试了一个独立的Java类,其中有:
1. List x = new ArrayList
2. List
#1 编译正常,但是 #2 给出一个错误:不兼容的类型 found: java.util.ArrayList
List
这令人困惑,但幸好通过Java Generics FAQ解决了这个谜团! 🙂
List extends Tree>,真的很棘手。
:以什么方式?我不确定你的评论想要表达什么。
作为一个Java新手,我从来没有见过这样的用法。对我来说,这似乎有点复杂。
:啊,我明白了。我建议你阅读一下Java泛型教程-你会经常见到这个的。
如果我没有理解错,<?extends T>表示我们可以将任何T的子类型放入一个集合中。那么如何将两个子类T的列表合并成一个T的列表?
:对,就是这个意思。然后假设U extends T和V extends T,如果我们有一个List和一个List
:是的,应该是可行的...如果你在实现时有困难,请提一个新问题并提供详细信息。