结合深层通用集合

时间:2014-01-26 01:45:23

标签: java generics

使用以下Java代码,是否有办法在第二级将集合与相关的通用参数组合在一起?:

public class Tester {

    interface Base{};
    class A implements Base{}
    class B implements Base{}

    @Test
    public void test(){
        Map<String, List<A>> a = new HashMap<String, List<A>>();
        Map<String, List<B>> b = new HashMap<String, List<B>>();

        Map<String, Base> bases = combine(a, b);
    }

    private Map<String, List<Base>> combine(Map<String, List<? extends Base>> one, Map<String, List<? extends Base>> two) {
        Map<String, List<Base>> bases = new HashMap<String, List<Base>>();

        bases.putAll(one);
        bases.putAll(two);

        return bases;
    }
}

问题是combine()方法不会将Map<String, List<A>>Map<String, List<? extends Base>>匹配,即使A扩展Base而bases.putAll()也不会接受Map<String, List<? extends Base>>的类型

3 个答案:

答案 0 :(得分:3)

第一个问题,在combine()中,您的bases被声明为

Map<String, List<Base>>

但是试图放一个

Map<String, List<? extends Base>>

List<? extends Base>不是List<Base>的子类型,就像List<A>不是List<Base>的子类型一样。

要解决此问题,请将bases中的combine更改为

类型
Map<String, List<? extends Base>> bases = new HashMap<String, List<? extends Base>>();

现在putAll方法接受任何扩展List<? extends Base>的类型。 List<? extends Base>List<? extends Base>的子类型。

当你修复它时,你有另一个问题,你的combine方法返回类型。它现在必须是

Map<String, List<? extends Base>>

以便它可以匹配bases声明。

这会产生第三个问题。 Map<String, List<A>>不是Map<String, List<? extends Base>>类型参数的有效参数。您可以将参数更改为键入

Map<String, ? extends List<? extends Base>>

现在Map<String, List<A>>可以作为参数传递。

最后,它看起来像

@Test
public void test() {
    Map<String, List<A>> a = new HashMap<String, List<A>>();
    Map<String, List<B>> b = new HashMap<String, List<B>>();
    Map<String, List<? extends Base>> bases = combine(a, b);
}

private Map<String, List<? extends Base>> combine(
        Map<String, ? extends List<? extends Base>> one,
        Map<String, ? extends List<? extends Base>> two) {
    Map<String, List<? extends Base>> bases = new HashMap<String, List<? extends Base>>();

    bases.putAll(one);
    bases.putAll(two);
    return bases;
}

但老实说,你真的需要那么多级别吗?尽量让你的生活更轻松,如果可能的话,使用像Bohemian建议的那样。

答案 1 :(得分:1)

此处的问题是,对于通用,List<Subclass> List<Superclass>的实例。

要使代码生效,请将源地图的值类型更改为List<Base> - 您仍然可以将AB的实例添加到List<Base>

public void test() {
    Map<String, List<Base>> a = new HashMap<String, List<Base>>();
    Map<String, List<Base>> b = new HashMap<String, List<Base>>();

    Map<String, List<Base>> bases = combine(a, b);
}

private Map<String, List<Base>> combine(Map<String, List<Base>> one, Map<String, List<Base>> two) {
    Map<String, List<Base>> bases = new HashMap<String, List<Base>>();
    bases.putAll(one);
    bases.putAll(two);

    return bases;
}

答案 2 :(得分:0)

考虑允许你在联合(...)

中做什么
one.put("xxx", new ArrayList<B>());

这是有效的,因为声明是Map<String, List<? extends Base>>。如果您被允许通过Map<String, List<A>>,那么您可以混合类型。

如果您将参数更改为Map<String, ? extends List<? extends Base>>,那么上面的示例不是有效的代码行,您将被允许将Map<String, List<A>>传递给合并(..)。