【问题标题】:java interface generics casting problemjava接口泛型转换问题
【发布时间】:2011-02-05 08:21:41
【问题描述】:

类型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,那么错误就会消失,这是没有意义的,因为它必须对函数返回类型进行完全相同的强制转换。

【问题讨论】:

  • 你的objects不应该被实例化为new ArrayList&lt;IDerived&gt;()吗?
  • @biziclop,为什么不将其发布为答案?
  • 我的回答可能太过分了。我以为你在问为什么与如何修复它。
  • @finnw 因为我手头没有 Eclipse 来测试它是否可以编译,所以我没有时间写一个解释。

标签: java generics


【解决方案1】:

试试这个:

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...如果这确实是他们想要的,调用者总是可以将结果转换/存储为List&lt;? extends IObject&gt;
  • 哦,等等,我没有在中间看到未经检查的演员表。这有点恶心。
【解决方案2】:

我不知道我是否会正确解释这一点,但我开始了。

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

表示列表是扩展 IObject 的未知类型。即使您在 rhs 上放置了 new ArrayList&lt;IObject&gt;();,列表泛型类型仍然没有严格定义。换句话说,泛型类型在您为其分配引用时不会被“烘焙”。

因此,当您调用 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

【讨论】:

    【解决方案3】:

    为什么是通配符?代替? 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()
    

    【讨论】:

      猜你喜欢
      • 2014-05-03
      • 2013-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2012-09-02
      相关资源
      最近更新 更多