【问题标题】:Cannot cast from List<Node> to List<Element>无法从 List<Node> 转换为 List<Element>
【发布时间】:2018-11-06 06:07:08
【问题描述】:

每个人。 我正在练习 dom4j 和 Xpath,但遇到了一个问题。

我正在尝试:

List<Element> conList = (List<Element>)doc.selectNodes("//contact");

但出现错误:

Cannot cast from List<Node> to List<Element>

代码在教学视频中似乎运行良好, 但在我的电脑上不起作用。

这是一种非法操作吗? 我可以通过其他方式解决问题吗? 谢谢。

【问题讨论】:

  • 不是重复的,那个问题是关于向上转换的,这个是关于向下转换/缩小的
  • dom4j 1.6.1 selectNodes() 返回了一个 List,在 dom4j 2.1.1 中它返回一个 List,这意味着从 selectNodes() 填充 List 的任何现有代码都不会编译,并且需要返工(例如从节点向下转换到元素)

标签: java xpath dom4j


【解决方案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());

【讨论】:

    【解决方案2】:

    这是一个令人沮丧的问题,因为您知道(从 XPath 表达式的语义)列表中的项目都将是 Element 的实例,但是没有办法告诉 Java 编译器。如果 DOM4J 的设计者考虑得更仔细一点,他们会将结果声明为 List&lt;? extends Node&gt;,这会给您更多的灵活性(尽管强制转换仍然会给您编译器警告)。这也令人沮丧,因为该规则的原因都是关于将不适当的项目添加到列表中的危险,而您真正想要的是一个不应该出现问题的不可变列表(尽管它仍然存在,因为泛型不处理特别是不可变集合)。

    @MagnusLutz 提供的干净解决方案将满足编译器的要求,但它很昂贵 - 它涉及复制列表。

    在 Saxon 9.9 中,我设计了一个新的 API,它试图很好地与泛型配合使用,并且它适用于 DOM4J,所以试一试。它还避免了为像这样的简单情况编译/解释 XPath 表达式的成本。但是(遗憾的是)它并没有解决泛型的潜在限制,尤其是与 XPath 表达式这样的构造相关,其中 XPath 编译器可用的类型信息无法与 Java 编译器共享。

    您实际上想对这些元素做什么?如果我需要将列表传递给需要List&lt;Element&gt; 的方法,那么我可能会使用@MagnusLutz 的解决方案。如果我只想处理元素,我会这样做

    for (Node n : doc.selectNodes("//contact")) {
       Element e = (Element)n;
       ...
    }
    

    【讨论】:

    • 如果他只想处理元素,他仍然可以使用流的.foreach,同样不需要创建列表的副本。虽然流可能会有更多的内部开销
    猜你喜欢
    • 1970-01-01
    • 2013-06-12
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多