使用通配符返回通用类型对象列表

时间:2014-03-13 02:23:38

标签: java generics collections

要求:

  • 需要我的方法返回两个指定对象之一的List。
  • 需要将上述方法的结果存储为两个指定对象之一的List。

声明了一个基于通配符返回通用列表的方法。 声明部分正确,但方法调用失败。

class Z{/*TemplateClass*/}
public class A extends Z{}
public class B extends Z{}

测试类:

public List<? extends Z> getGenericList(boolean test){
    if(test){
        List<A> aList = new ArrayList<A>();
        aList.add(new A());
        return aList;
    }
    else{
        List<B> bList = new ArrayList<B>();
        bList.add(new B());
        return bList;
    }
}

这是我的要求。我需要类似下面的代码。

List<A> testAList = getGenericList(true);
List<B> testBList = getGenericList(false);

给我一​​个编译器错误。

  

类型不匹配:无法从List&lt;转换捕获#1?延伸Z>至   列表与LT; A&gt;类型不匹配:无法从List&lt;转换捕获#2?扩展   Z>列出&lt; B&gt;

我理解这背后的逻辑。如果我们传递错误并将返回的B列表存储为错误的A列表,该怎么办? 但是当我使用下面的代码时:

List<? extends Z> testList = getGenericList(true);

编译好。但它击败了我的目的。我无法访问A或B中的方法,因为testList.get(index)返回Z类型的对象,我希望得到A或B.

如果我的代码绝对错误,那么任何正确方向的指针都会受到赞赏。

2 个答案:

答案 0 :(得分:3)

您可以转换结果,这会导致编译器错误消失,但您有一个看似代码味道的不安全转换:

List<A> testAList = (List<A>) getGenericList(true);
List<B> testBList = (List<B>)getGenericList(false);

此外,如果布尔输入不是严格要求,您也可以这样做:

public <T extends Z> List<T> getGenericList(Class<T> klass) {
        List<T> list = new ArrayList<T>();
        try {
            list.add(klass.newInstance());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return list;
    }

答案 1 :(得分:1)

不会发生。您要求的类型无法在java类型系统中表达,例如List<A> + List<B>

最接近的是一种延续传递方式;您使用访问者界面和接受方法创建另一个抽象类,如HomogeneousListAB。然后你可以从getGenericList返回其中一个。

abstract class HomogeneousListAB {
    interface Visitor {
        void ifListA( List< A > la );
        void ifListB( List< B > la );
    }
    abstract public accept( Visitor v );
}

// inside getGenericList true branch
final List< A > laOut = // whatever
return new HomogeneousListAB() {
    public accept( Visitor v ) {
        v.ifListA( laOut );
    }
};