【问题标题】:Cast element in Java For Each statementJava For Each 语句中的 Cast 元素
【发布时间】:2011-01-29 15:13:39
【问题描述】:

是否可以(甚至可取)将从 a for each 语句中检索到的元素转换为语句本身?我知道列表中的每个元素都是<SubType> 类型。

IE:

List<BaseType> list = DAO.getList();  
for(<SubType> element : list){ 
    // Cannot convert from element type <BaseType> to <SubType>
    ...
}

而不是:

List <BaseType> list = DAO.getList();
for(<BaseType> el : list){
    <SubType> element = (<SubType>)el;
    ...
}

【问题讨论】:

    标签: java foreach casting


    【解决方案1】:

    真的知道每个条目都会是一个子类型吗? DAO 只需履行List&lt;BaseType&gt; 合同,如果你假设一个子类,那么我认为某处有问题。我可能会更专注于让 DAO 的接口正确,并让它以合同方式返回你想要的东西。

    【讨论】:

    • +1 如此雄辩地说明接口应遵守的契约机制。
    • 不幸的是,DAO 代码不是我们的。但是,数据源的馈送是。我们将 子类化(唯一的此类子类),因为我们希望在该类中具有附加功能。由于我们控制输入并且我们只是将 对象放在那里,我觉得我可以相当肯定检索到的对象实际上是 之一。如果我们控制了所有代码,那么您将 100% 正确。
    • @Carl - 是否值得包装 DAO,并提供一个 不同的 接口来满足您的需求。否则你将不得不在你的代码库中进行所有转换(可能 - 我意识到我正在假设它的分布范围)
    • 啊,但总能只见树木不见森林。这很有意义。感谢您的建议,我会将其转达给做出此类决定的人。
    • 虽然这个“回复”将是一个非常有用的评论,但它根本没有回答这个问题。虽然示例说“我的 DAO 做得很差”,但问题要求解决每个元素转换的解决方案。这个答案根本没有涵盖它。例如,我喜欢将 javax.management.AttributeList 条目类型转换为实际的 Attribute,因为它出于某种奇怪的原因扩展了 ArrayList
    【解决方案2】:

    出于其他人所述的所有原因,您不应该这样做。但是,如果您无法更改界面,则可以进行以下操作:

    for (BaseType element : list) {
        SubType subType = (SubType)element;
        ...
    }
    

    据我所知,这是做到这一点并保持真正类型安全的唯一方法 - 即不依赖类型擦除来捕获任何问题,直到很久以后才会这样做。

    我知道这不是您想要的,但它确实可以处理转换。

    【讨论】:

    • 我应该注意,如果您可以更改接口,并且它始终是子类型,那么您应该更改接口,无论是通过子类扩展还是只是更改它。
    • 为了安全起见,你可以这样做:if(element instanceof SubType)
    • 非常正确 - 我应该这么说的。
    • 很好,这就是我一直在做的。我希望有一条更短的路,但我确实看到了没有这条路的智慧。
    • 遗憾的是它不能在 for-each 中正确完成,但我想这不是你经常需要的东西(除非你使用一些非常讨厌的代码)。
    【解决方案3】:

    实际上可以将强制转换与 for 循环结合起来,如下所示:

    List<BaseType> list = DAO.getList();  
    for (SubType subType : ((List<SubType>) list)){ 
        ...
    }
    

    或者你可以使用这个稍微干净一点的模式:

    List<SubType> list = (List<SubType>) DAO.getList();  
    for (SubType subType : list){ 
        ...
    }
    

    您会从 Java 编译器收到未经检查的强制转换警告,除非您禁止它。第一种形式的效果实际上与在循环中强制转换每个元素相同。第二种形式还将强制列表中的新增内容必须符合 SubType。

    请注意,这不适用于数组,因为数组具有不同的运行时类型。换句话说,BaseType[] 不能转换为 SubType[]。您可以使用 Arrays API 来解决此问题,如下所示:

    BaseType[] array = DAO.getArray();
    for (SubType subType : Arrays.<SubType>asList(array)) {
        ...
    }
    

    【讨论】:

    • 这些转换是不合法的,尽管您可以使用some tricks 来解决它(例如对List&lt;?&gt; 的中间转换。)从该问题链接的java tutorial 指出:“尽管整数是Number 的子类型,List 不是 List 的子类型,实际上这两种类型没有关系。List 和 List 的共同父级是 List>。”
    • 如果 DAO.getList 返回一个无类型列表而不是 List,则第二个示例将起作用。在处理没有输入任何集合的遗留代码库时,该模式很有用。
    【解决方案4】:

    可能,是的!但上帝保佑,为什么?我在职业生涯中的早期尝试就是这样做的,我已经学到了。对接口进行编程总是有优势的。我总是从初级开发人员那里收到关于处理只有子类型具有所需方法/功能的情况的问题。

    说动物类的狗子类型有方法 bark()。他们想要 bark() 功能。实际的挑战是他们想要一种动物交流的行为,而不是 bark() 而是动物 speak()。所以一个新的 Cat 子类不需要 meow()。那怎么办:-我的狗成群结队,但猫却没有。 answer pack() 行为不属于一只狗。包是一个不同的方面,将包传递给所有对象并要求对象加入包。 (访客模式/适配器模式)。我的 Wolf 类可以使用相同的行为。

    我对此是否固执,不,如果它只是 1 个实例,我很好。如果答案是我不确定,那么您最好通过接口合约来确保安全。

    【讨论】:

      【解决方案5】:

      如果您不偏爱 Google 收藏,可以使用 transform 方法包装列表。在您的情况下,它将非常有效且完全合规。尽管按照 Brian 的建议,我会将其作为包装方法。

      public List< SubType > fromDao ( )
      {
          // Put a comment for maintainer
      
          // Lists from DAO always contain SubTypes
          return
              Lists.transform(
                  DAO.getList( ),
                  new Function< BaseType, SubType >( )
                  {
                      public SubType apply ( final BaseType from )
                      {
                          return (SybType) from;
                      }
                  };
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-26
        • 2017-01-23
        • 2014-07-21
        • 1970-01-01
        • 2016-10-24
        • 2018-08-22
        • 2016-01-02
        相关资源
        最近更新 更多