java界面泛型投射问题

时间:2011-02-04 18:43:46

标签: java generics

类型List中的方法add(capture#2-of?extends IObject)不适用于参数(IDerived)

protected List<? extends IObject> getObjects()
{
    List<? extends IObject> objects = new ArrayList<IObject>();
    for (String id: item_ids)
    {
        IDerived object = (IDerived) readObject(id);
        objects.add(object); #error
    }
    return objects;
}

interface IDerived extends interface IVersionedObject extends interface IObject

如果我将对象的类型更改为List,那么错误就会消失,这没有任何意义,因为它必须对函数返回类型进行完全相同的转换。

3 个答案:

答案 0 :(得分:7)

试试这个:

protected <T extends IObject> List<T> getObjects() {
    List<T> objects = new ArrayList<T>();
    for (String id: item_ids)
    {
        T object = (T) readObject(id);
        objects.add(object); // NO error
    }
    return objects;
}

编辑(简短说明):

这样你的方法可以适用于IObject的任何子类型(里面的列表和强制转换都是通用的),返回类型将从调用者的期望中推断出来(正如你明显的意图)。

在回复注释时,您现在可以通过以下方式调用getObjects()方法:

// This should only be used if readObject() behaves like
// getObjects() and is able to return any requested subtype.
// Otherwise, you'll get a ClassCastException when trying to get
// something from the derivedList in case readObject() put something
// else there (which is not a subtype of IDerived).
List<IDerived> derivedList = getObjects();

// This is the safe way to go in case you don't have
// full control over what readObject() returns.
// But if you're using it like this (all the time), you'd better
// return List<IObject> from getObjects() and get rid
// of generics.
List<? extends IObject> objectList1 = getObjects();
List<IObject> objectList2 = getObjects();

答案 1 :(得分:4)

我不知道我是否会解释这个问题,但我会去。

List<? extends IObject> objects = new ArrayList<IObject>();

说该列表是一个扩展IObject的未知类型。即使您在rhs上放置new ArrayList<IObject>();,列表泛型类型仍未严格定义。换句话说,当您为其分配引用时,泛型类型不会被“烘焙”。

因此,当您致电objects.add(object);时,类型检查程序不知道该列表将与IDerived兼容,因为该列表可能是IVersionedObjectSomethingElse类型。即使你从逻辑流程中发现这是不可能的,也可以构建。

List<? extends IObject> objects = null;
if (test) { 
    objects = new ArrayList<IObject>();
}
else {
    objects = new ArrayList<IVersionedObject2>();
}

objects.add( (IDerived) iDerivedObj ); // iDerived *might* not be compatible

答案 2 :(得分:0)

为什么要使用通配符?而不是? extends IObject,请使用IDerived

更改此行

List<? extends IObject> objects = new ArrayList<IObject>();

到此:

List<IDerived> objects = new ArrayList<IDerived>();

并改变

protected List<? extends IObject> getObjects()

protected List<IDerived> getObjects()