java 如何将子对象集合类型转换为父对象集合

8e2ybdfx  于 2023-05-12  发布在  Java
关注(0)|答案(3)|浏览(273)

我有一个基类

public class BaseInfo { }

然后我有两个来自BaseInfo的子类:

public class FunctionInfo extends BaseInfo {}
public class ComponentInfo extends BaseInfo {}

现在,在休息层有一个方法,使用它我可以得到这些子对象的集合类似下面

Map<String, List<ComponentInfo>> allCompInfo  = componentLayer.findById(Id, true);  
Map<String, List<FunctionInfo>> allFunctionInfo = functionLayer.findById(Id);

在我的下一个方法中,我必须发送allCompInfo和allFunctionInfo来获取下一个信息。或者我必须调用两次该方法,如果我不同时发送它们。在这两种情况下,操作复杂度是相同的。迭代两个集合列表。
我很想知道是否有任何方法可以将两个子对象集合都收集到BaseInfo集合中。比如

Map<String, List<BaseInfo>> allInfo  = componentLayer.findById(Id, true);
     allInfo = functionLayer.findById(Id);

基本上铸造我试过,但收集看起来像工作不同的方式。有没有什么方法可以将整个子集合类型转换为父集合。如果有人能帮上忙,那就太好了。

mwkjh3gx

mwkjh3gx1#

List<Component>List<Function>只是List<BaseInfo>的***而不是***子类型。如果它们是一个子类型,那么你可以对List<BaseInfo>做的一切也可以对List<Component>做,对吗?但事实并非如此-您可以将Function添加到List<BaseInfo>,但不能将Function添加到List<Component>。阅读更多关于here的信息。
List<Component>List<Function> * 是List<? extends BaseInfo>的 * 子类型。List<? extends BaseInfo>List<BaseInfo>非常相似,但不能向其添加元素(null除外)。您可以将这两个Map合并为Map<String, List<? extends BaseInfo>>,如下所示:

var map = new HashMap<String, List<? extends BaseInfo>>(allFunctionInfo);
for (var entry : allCompInfo.entrySet()) {
    map.merge(entry.getKey(), entry.getValue(), (x, y) -> {
        // when keys collide, create a new List<BaseInfo> with elements from both lists
        var list = new ArrayList<BaseInfo>(x);
        list.addAll(y);
        return list;
    });
}

或者,您可以为每个List<Function>和每个List<Component>创建副本。副本的类型可以是List<BaseInfo>

var map = new HashMap<String, List<BaseInfo>>();
for (var entry : allCompInfo.entrySet()) {
    // new ArrayList<>(anotherList) creates a copy
    map.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
for (var entry : allFunctionInfo.entrySet()) {
    map.merge(entry.getKey(), new ArrayList<>(entry.getValue()), (x, y) -> {
        x.addAll(y);
        return x;
    });
}

您可以将其提取到适用于任何基类型和两个子类型的泛型方法:

private static <TBase, TSub1 extends TBase, TSub2 extends TBase> 
Map<String, List<TBase>> merge(Map<String, List<TSub1>> map1, Map<String, List<TSub2>> map2) {
    var map = new HashMap<String, List<TBase>>();
    for (var entry : map1.entrySet()) {
        map.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    for (var entry : map2.entrySet()) {
        map.merge(entry.getKey(), new ArrayList<>(entry.getValue()), (x, y) -> {
            x.addAll(y);
            return x;
        });
    }
    return map;
}
o75abkj4

o75abkj42#

如果没有“密钥”冲突(https://www.baeldung.com/java-hashmap-advanced#collisions-in-the-hashmap),那么可以尝试这种方法:

Map<String, List<? extends BaseInfo>> allInfos = new HashMap<>();
allInfos.putAll(compoments);
allInfos.putAll(functions);
wswtfjt7

wswtfjt73#

您必须创建一个新的List<BaseInfo>并复制子类对象。
所以这个答案是广泛有用的,在这里我使用了JDK中更熟悉的类,而不是您的自定义类:父类Number和子类IntegerLong
给出:

Map<String, List<Integer>> allCompInfo  = new HashMap<>();
Map<String, List<Long>> allFunctionInfo = new HashMap<>();

你想用它们填充一个Map<String, List<Number>> allInfo
或者强制性地将所有值复制到基本Map中,手动处理合并:

Map<String, List<Number>> allInfo = new HashMap<>();
allCompInfo.forEach((k, v) -> v.forEach(e -> allInfo.merge(k, new ArrayList<>(List.of(e)), (a,b) -> { a.addAll(b); return a;})));
allFunctionInfo.forEach((k, v) -> v.forEach(e -> allInfo.merge(k, new ArrayList<>(List.of(e)), (a,b) -> { a.addAll(b); return a;})));

或者,通过流在一行中执行,如果添加更多的子类,扩展性会更好(而且看起来更酷):

Map<String, List<Number>> baseInfo = Stream.of(allCompInfo, allFunctionInfo)
   .map(Map::entrySet)
   .flatMap(Set::stream)
   .flatMap(e -> e.getValue().stream().map(v -> new AbstractMap.SimpleEntry<String, Number>(e.getKey(), v)))
   .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));

相关问题