【问题标题】:How can I cast a list using generics in Java?如何在 Java 中使用泛型转换列表?
【发布时间】:2009-03-19 14:53:23
【问题描述】:

请考虑以下 sn-p:

public interface MyInterface {

    public int getId();
}

public class MyPojo implements MyInterface {

    private int id;

    public MyPojo(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

}

public ArrayList<MyInterface> getMyInterfaces() {

    ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
    myPojos.add(new MyPojo(0));
    myPojos.add(new MyPojo(1));

    return (ArrayList<MyInterface>) myPojos;
}

return 语句进行了无法编译的强制转换。如何将 myPojos 列表转换为更通用的列表,无需遍历列表中的每个项目

谢谢

【问题讨论】:

    标签: java generics casting


    【解决方案1】:

    更改您的方法以使用通配符:

    public ArrayList<? extends MyInterface> getMyInterfaces() {    
        ArrayList<MyPojo> myPojos = new ArrayList<MyPojo>(0);
        myPojos.add(new MyPojo(0));
        myPojos.add(new MyPojo(1));
    
        return myPojos;
    }
    

    这将阻止调用者尝试将接口的其他实现添加到列表中。或者,您可以只写:

    public ArrayList<MyInterface> getMyInterfaces() {
        // Note the change here
        ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
        myPojos.add(new MyPojo(0));
        myPojos.add(new MyPojo(1));
    
        return myPojos;
    }
    

    如 cmets 中所述:

    • 返回通配符集合对调用者来说可能很尴尬
    • 通常最好使用接口而不是返回类型的具体类型。所以建议的签名可能是以下之一:

      public List<MyInterface> getMyInterfaces()
      public Collection<MyInterface> getMyInterfaces()
      public Iterable<MyInterface> getMyInterfaces()
      

    【讨论】:

    • 第二个解决方案是更好的恕我直言。返回通配符通常被认为是不好的做法,因为它限制了客户端代码。在这种情况下使用 ArrayList extends MyInterface> 你只能从列表中读取,不能添加任何东西。
    • 当然,这可能是我们想要的——我们只是不知道。 (它几乎肯定也应该使用 List 而不是 ArrayList,或者可能只使用 Iterable 或 Collection。)
    • +1 用于使用更通用的类型(例如 List、Collection)。但是返回通配符很少是你想要的。如果您倾向于不变性,那么有更好的方法来做到这一点。 Naftalin 和 Wadler 在“Java 泛型和集合”中谈到了这一点。
    • 与 C# 相比,Java 对泛型的处理很糟糕。将 Dog 添加到 Animals 列表中应该是完全有效的。
    • @csmith:将Dog 添加到List&lt;Animal&gt; 是完全有效的。我同意 C# 的泛型要好得多,但您评论的第二部分是非基础 IMO。
    【解决方案2】:

    最好从一开始就选择正确的类型,但是要回答您的问题,您可以使用类型擦除。

    return (ArrayList&lt;MyInterface&gt;) (ArrayList) myPojos;

    【讨论】:

    • IMO,这应该是答案,因为在某些情况下,您根本无法将项目添加到基本类型的集合中:想想查询中的 JPA 结果集,您会得到一个列表JPA 实体,如果您想使用实体上方的一些抽象接口(持久性不可知)将此列表返回给调用者,彼得的建议是 方式
    【解决方案3】:

    你应该这样做:

    public ArrayList<MyInterface> getMyInterfaces() {   
       ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);    
       myPojos.add(new MyPojo(0));    
       myPojos.add(new MyPojo(1));    
       return myPojos;
    }
    

    【讨论】:

      【解决方案4】:

      在这种情况下,我会这样做:

      public ArrayList<MyInterface> getMyInterfaces() {
      
          ArrayList<MyInterface> myPojos = new ArrayList<MyInterface>(0);
          myPojos.add(new MyPojo(0));
          myPojos.add(new MyPojo(1));
      
          return myPojos;
      }
      

      MyPojo 是 MyInterface 类型的(因为它实现了接口)。这意味着,您可以使用所需的接口创建列表。

      【讨论】:

        【解决方案5】:

        尝试在任何地方都使用接口,除了在构造实例时,你的问题就会消失:

        public List<MyInterface> getMyInterfaces()
        {
            List<MyInterface> myInterfaces = new ArrayList<MyInterface>(0);
            myInterfaces.add(new MyPojo(0));
            myInterfaces.add(new MyPojo(1));
        
            return myInterfaces;
        }
        

        正如其他人已经说过的,使用 MyInterface 可以解决您的问题。 对于返回类型和变量,最好使用 List 接口而不是 ArrayList。

        【讨论】:

        • 使用 List 并不能解决问题 - 它是使用 MyInterface 而不是 MyPojo 作为类型参数。
        • 是的,那是误导,现在修复它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-02
        • 2021-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多