开发者

java interface generics casting problem

The method add(capture#2-of ? extends IObject) in the type List is not applicable for the arguments (IDerived)

protected List<? extends IObject> getObjects()
{
    List<? extends IObject> objects = new开发者_如何学Python 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

If I change the type of objects to List then the error goes away, which makes no sense because it has to make exactly the same cast to the function return type.


Try this:

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;
}

EDIT (short explanation):

This way your method will work fine with any subtype of IObject (the lists and casts inside get to be generic) and the return type will be inferred from the caller's expectations (as you apparently intended).

In response to the comment, you can now call the getObjects() method in the following ways:

// 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();


I don't know if I am going to explain this right but here I go.

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

Says that the list is of an unknown type that extends IObject. Even though you put a new ArrayList<IObject>(); on the rhs, the list generic type is still not tightly defined. In other words, the generic type does not get "baked" in when you assign a reference to it.

So, when you call objects.add(object); The type checker doesn't know that the list will be compatible with IDerived because the list could be of type IVersionedObjectSomethingElse. Even though that's impossible from you flow of logic it's possible to constuct.

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


Why the wildcards? Instead of ? extends IObject, use IDerived

Change this line

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

to this:

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

And change

protected List<? extends IObject> getObjects()

to

protected List<IDerived> getObjects()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜