每个人。 我正在练习dom4j和Xpath,但是遇到了问题。
我正在尝试:
List<Element> conList = (List<Element>)doc.selectNodes("//contact");
但出现错误:
Cannot cast from List<Node> to List<Element>
该代码在教学视频中似乎运行良好, 但无法在我的计算机上工作。
这是一种非法操作吗? 我可以通过其他方式解决问题吗? 谢谢。
答案 0 :(得分:1)
您不能简单地以这种方式使用具有具体参数的泛型对象。
实现目标的一种很好的java8方法是:
List<Element> conList = doc.selectNodes("//contact")
.stream()
.map(node->(Element)node)
.collect(Collectors.toList());
请注意,对于通常不知道列表元素是否实际上是目标类或接口的实例的一般情况,您可能希望通过过滤来断言
List<Element> conList = doc.selectNodes("//contact")
.stream()
.filter(node->node instanceof Element)
.map(node->(Element)node)
.collect(Collectors.toList());
答案 1 :(得分:1)
这是一个令人沮丧的问题,因为您(从XPath表达式的语义)知道列表中的项目都是Element
的实例,但是无法告诉Java编译器。如果DOM4J的设计人员经过了更加仔细的考虑,他们会将结果声明为List<? extends Node>
,这将为您提供更多的灵活性(尽管强制转换仍会向您提供编译器警告)。这也是令人沮丧的,因为该规则的原因是关于在列表中添加不合适的项目的危险,而您真正想要的是一个不可变列表,其中不应出现问题(尽管它仍然存在,因为泛型不不可变集合)。
@MagnusLutz提供的干净解决方案可以满足编译器的要求,但是它很昂贵-它涉及到复制列表。
在Saxon 9.9中,我设计了一个新的API,该API尝试与泛型很好地配合使用,并且可以与DOM4J一起使用,因此请尝试一下。对于像这样的简单情况,它还避免了编译/解释XPath表达式的开销。但是(遗憾的是)它不能解决泛型的基本限制,特别是对于XPath表达式之类的构造,其中XPath编译器可用的类型信息无法与Java编译器共享。
您实际上想对元素做什么?如果我需要将列表传递给需要List<Element>
的方法,那么我可能会使用@MagnusLutz的解决方案。如果我只想处理这些元素,我会做
for (Node n : doc.selectNodes("//contact")) {
Element e = (Element)n;
...
}