Java 克隆列表地图的有效方法?

Java 克隆列表地图的有效方法?,java,dictionary,Java,Dictionary,对于我的项目,我需要一种字典类型,我可以通过键访问值列表,但也可以通过值获取键。为了实现这一点,我创建了一个包含两个哈希映射的新类: private final Map<K, List<V>> kvMap; private final Map<V, K> vkMap; 我也希望能够克隆这种地图。我目前的解决办法是 public InverseSurjectiveMap(InverseSurjectiveMap<K, V> map) { t

对于我的项目,我需要一种字典类型,我可以通过键访问值列表,但也可以通过值获取键。为了实现这一点,我创建了一个包含两个哈希映射的新类:

private final Map<K, List<V>> kvMap;
private final Map<V, K> vkMap;
我也希望能够克隆这种地图。我目前的解决办法是

public InverseSurjectiveMap(InverseSurjectiveMap<K, V> map) {
    this.kvMap = new HashMap<>(map.kvMap);

    for (K key : map.kvMap.keySet()) {
        kvMap.put(key, new LinkedList<>(kvMap.get(key)));
    }

    this.vkMap = new HashMap<>(map.vkMap);
}
有没有一种时间效率更高的复制方法:降低时间复杂度而不是内存复杂度。谢谢

编辑: 我需要的是,更改初始映射的列表不会更改复制映射的列表,反之亦然。我希望实际元素引用相同的实例。

您可以使用映射方法:

this.kvMap = new HashMap<>(map.kvMap);
this.kvMap.replaceAll((k, v) -> new ArrayList<>(v));
正如markspace所指出的,这将克隆列表,但如果您的键和值本身是可变的,则必须单独克隆它们,才能使您的映射成为完整克隆。

您可以使用映射方法:

this.kvMap = new HashMap<>(map.kvMap);
this.kvMap.replaceAll((k, v) -> new ArrayList<>(v));
正如markspace所指出的,这将克隆列表,但如果您的键和值本身是可变的,则必须单独克隆它们才能使地图成为完整克隆。

编辑:

我想这是最快的方法之一

@SuppressWarnings("unchecked")
public static <K, V, T extends Collection<V>> Map<K, T> deepCopy(Map<K, ? extends Collection<V>> map) {
    Map<K, Collection<V>> cMap = new HashMap<>(map);
    for (Map.Entry<K, Collection<V>> entry : cMap.entrySet()) {
        Collection<V> list = entry.getValue();
        list = new ArrayList<>(list);
        entry.setValue(list);
    }
    return (Map<K, T>) cMap;
}
您可以将ArrayList更改为LinkedList编辑:

我想这是最快的方法之一

@SuppressWarnings("unchecked")
public static <K, V, T extends Collection<V>> Map<K, T> deepCopy(Map<K, ? extends Collection<V>> map) {
    Map<K, Collection<V>> cMap = new HashMap<>(map);
    for (Map.Entry<K, Collection<V>> entry : cMap.entrySet()) {
        Collection<V> list = entry.getValue();
        list = new ArrayList<>(list);
        entry.setValue(list);
    }
    return (Map<K, T>) cMap;
}
您可以将ArrayList更改为LinkedList,这是另一种方法:

this.kvMap = new HashMap<>(map.kvMap.size());
map.kvMap.forEach((k, v) -> this.kvMap.put(k, new ArrayList<>(v)));
它与非常类似,但在调用put时只创建一次条目。

还有另一种方法:

this.kvMap = new HashMap<>(map.kvMap.size());
map.kvMap.forEach((k, v) -> this.kvMap.put(k, new ArrayList<>(v)));

它非常类似于,但在调用put时会创建一次条目。

我想首先要指出的是,它不会复制任何元素K或V。您复制映射和列表,但它们指向的元素是原始元素。只能复制对图元的引用。如果可以的话,那就可以了。但我想指出的是,在Java中,有很多方法可以使用深度或浅层复制和流复制映射。是的,我需要的是更改初始映射的列表不会更改复制映射的列表,反之亦然。我希望实际元素引用相同的实例。我将进行编辑以澄清。我想首先要指出的是,这不会复制任何元素K或V。您复制地图和列表,但它们指向的元素是原始元素。只能复制对图元的引用。如果可以的话,那就可以了。但我想指出的是,在Java中,有很多方法可以使用深度或浅层复制和流复制映射。是的,我需要的是更改初始映射的列表不会更改复制映射的列表,反之亦然。我希望实际元素引用相同的实例。我将进行编辑以澄清。与其他答案相比,这是否具有更低的内存复杂度?@Ethathoma内存复杂度是相同的,但在我的答案中,条目添加了一次。在另一个答案中,首先从另一个映射创建条目,然后替换每个条目。与另一个答案相比,这具有更低的内存复杂性。那么@Ethathoma内存复杂性是相同的,但在我的答案中,条目只添加一次。在另一个答案中,首先从另一个映射创建条目,然后替换每个条目