java:当SomeClass实现SomeInterface </someinterface> </someclass>时,从List <someclass>转换为List <someinterface>

时间:2011-02-10 15:18:57

标签: java generics

我有一个大脑抽筋:我有一个public interface SomeInterface和一个static private class SomeClass我正试图从我的一个方法中返回List<SomeInterface>,但是我得到了错误(在下面的return list;行:

Type mismatch: cannot convert from List<GenericList1.SomeClass> to
List<GenericList1.SomeInterface>

如何在不创建新列表的情况下解决此问题?

澄清:我不希望将列表创建为List<SomeInterface>(也许是显而易见的解决方案),因为我私下想要维护List<SomeClass>以允许将来访问SomeClass的方法超出了公共接口中的方法。这在下面的示例中没有显示,但在我的真实程序中我需要这个。

import java.util.ArrayList;
import java.util.List;

public class GenericList1 {

    public interface SomeInterface
    {
        public int getX();
    }

    private static class SomeClass implements SomeInterface
    {
        final private int x;
        @Override public int getX() {
            return this.x;
        }       
        public SomeClass(int x) { this.x = x; }
    }

    public static void main(String[] args) {
        List<SomeInterface> list = createList(10);
        printList(list);
    }

    private static void printList(List<SomeInterface> list) {
        for (SomeInterface si : list)
            System.out.println(si.getX());
    }

    private static List<SomeInterface> createList(int n) {
        List<SomeClass> list = new ArrayList<SomeClass>();
        for (int i = 0; i < n; ++i)
            list.add(new SomeClass(i));
        return list;
    }
}

4 个答案:

答案 0 :(得分:24)

您应该将方法重新定义为

private static List<? extends SomeInterface> createList(int n) { ...

,同样,其他列表声明。这允许您以多态方式处理通用列表,只要您只读取它们的值

(如果您想将新元素添加到列表中,则应使用List<? super SomeInterface>代替。)

这个成语以缩写 PECS - Producer:Extends / Consumer:Super 而闻名,由Josh Bloch在Effective Java 2nd Edition,Item 28中创造。

正如其他人所指出的那样,这个习惯用法是必需的,因为List<SomeClass> 一个List<SomeInterface>,即使SomeClass implements SomeInterface也是如此。其原因在参考文件中有详尽解释。

答案 1 :(得分:6)

与普遍看法相反,List<Derived>List<Base>完全没有关系,即使Derived extends Base也是如此。

仅仅因为类共享层次结构并不意味着它们的集合可以。对于泛型一般来说都是如此。

您可以按如下方式更改代码:

private static List<SomeInterface> createList(int n) {
        List<SomeInterface> list = new ArrayList<SomeInterface>();
        for (int i = 0; i < n; ++i)
            list.add(new SomeClass(i)); //add a SomeClass object - valid, because it has the interface
    return list;
}

答案 2 :(得分:1)

我会像这样更改方法的签名:

private static void printList(List<? extends SomeInterface> list) {
    for (SomeInterface si : list)
        System.out.println(si.getX());
}

private static <T super SomeClass> List<T> createList(int n) {
    List<T> list = new ArrayList<T>();
    for (int i = 0; i < n; ++i)
        list.add(new SomeClass(i));
    return list;
}

在返回类型中使用通配符通常是一个坏主意,因为它会强制您在所有调用方法中使用通配符。我使createList成为一个通用方法,以便返回类型尽可能灵活,同时尽可能具体。

答案 3 :(得分:0)

private static List<SomeInterface> createList(int n) {
    List<SomeInterface> list = new ArrayList<SomeInterface>();
    for (int i = 0; i < n; ++i)
        list.add(new SomeClass(i));
    return list;
}