是否有可能使这个功能一致?

时间:2014-03-18 13:33:48

标签: java generics covariance

由于Java中的协方差规则,我无法创建此通用函数。我知道我可以使用通配符并执行List<? extends/super T>。我只是看不出它如何适用于这种情况。


  • 如果我想在此处传递dataItemsIterable<DataItem>,我不被允许,因为它们与类型IInterface不匹配,并且集合不是共变体。

  • 如果我将Map<String, List<IInterface>> target更改为<? extends IInterface>,那么由于显而易见的原因,我无法在底部拨打items.add(x);

  • 如果我将其更改为<? super IInterface>,那么函数很高兴,但我无法使用dataItems变量调用它,因为DerivedClass不是IInterface的超类。
  • 我可以正常使用

//DerivedClass implements IInterface which provides getId().
private Map<String, List<DerivedClass>> dataItems; 
private Map<String, List<OtherDerivedClass>> otherDataItems; 

private void populate(Map<String, List<IInterface>> target,
         Iterable<? extends IInterface> source) {
    for (final IInterface x : source) {
        List<IInterface> items = target.get(x.getId());
        if (items == null) target.put(x.getId(),
            new ArrayList<IInterface>(){{add(x);}});
        else items.add(x);
    }
}   

问题:我如何修改此功能以使其有效,或者如何更改我的基本设计?

2 个答案:

答案 0 :(得分:4)

您是否尝试为整个方法声明泛型类型参数?类似的东西:

private <I extends IInterface> void populate(Map<String, List<I>> target, Iterable<I> source)

答案 1 :(得分:1)

在@fge和@Ray建议的基础上,在您对该功能进行生成后,您可以使用您需要的任何类型调用它,例如

<IInterface>populate(...)

通常,此语法与静态函数一起使用

ClassName.<Type>getWhatever(...);

但没有什么能阻止你非静态地做这件事。

此外,如果您确实对该功能进行了一般化,您需要对其中的所有内容进行生成以反映该限制。意思是这样的

private <I extends IInterface> void populate(Map<String, List<I>> target,
         Iterable<I> source) {
    for (final I x : source) {
        List<I> items = target.get(x.getId());
        if (items == null) target.put(x.getId(),
            new ArrayList<I>(){{add(x);}});
        else items.add(x);
    }
}   

更多信息:http://java.dzone.com/articles/introduction-generics-java-%E2%80%93