135

我正在尝试保留一个包含 member 的类的临时容器:

HashMap<Integer,myObject> myobjectHashMap

一个名为 myobjectsList 的类

然后我做

myobjectsListA = new myobjectsList();
myobjectsListB = new myobjectsList();

然后:将一些哈希图项添加到 A(如 2)

然后:

myobjectListB = myobjectListA; //B has 2

然后:将 hashmap 项添加到 A(如 4 个以上)

然后:将A返回到B中存储的项目

myobjectListA = myobjectListb;

但是当我这样做时,B 与 A 一起增长,而我将 hashmap 项添加到 A。A 现在有 6 个项目,因为 B 有 6 个。

我希望 A 在最后一次分配后仍然有原来的 2。在 C++ 中我会使用对象的复制,java 的等价物是什么?

补充:好的,我遗漏了一些东西来解释这一点。MyObjectsList不包含 HashMap,它派生自MyBaseOjbectsList具有 HashMap 成员和MyObjectsListextends的类MyBaseOjbectsList。这有什么不同吗?

4

11 回答 11

256

如果你想要一份 HashMap 的副本,你需要用它来构造一个新的。

myobjectListB = new HashMap<Integer,myObject>(myobjectListA);

这将创建地图的(浅)副本。

于 2012-04-09T20:31:42.587 回答
15

你也可以使用

clone()

将所有元素从一个 hashmap 复制到另一个 hashmap 的方法

将所有元素从一个 hashmap 复制到另一个的程序

import java.util.HashMap;

public class CloneHashMap {    
     public static void main(String a[]) {    
        HashMap hashMap = new HashMap();    
        HashMap hashMap1 = new HashMap();    
        hashMap.put(1, "One");
        hashMap.put(2, "Two");
        hashMap.put(3, "Three");
        System.out.println("Original HashMap : " + hashMap);
        hashMap1 = (HashMap) hashMap.clone();
        System.out.println("Copied HashMap : " + hashMap1);    
    }    
}

来源: http ://www.tutorialdata.com/examples/java/collection-framework/hashmap/copy-all-elements-from-one-hashmap-to-another

于 2013-04-02T13:50:41.840 回答
13

不同之处在于,在 C++ 中,您的对象位于堆栈中,而在 Java 中,您的对象位于堆中。如果 A 和 B 是对象,那么在 Java 中的任何时候你都可以:

B = A

A 和 B 指向同一个对象,所以你对 A 做的任何事情都会对 B 做,反之亦然。

HashMap()如果您想要两个不同的对象,请使用 new 。

您可以使用Map.putAll(...)在两个地图之间复制数据。

于 2012-04-09T20:25:05.420 回答
6

这里有一个小的(巨大的)轻描淡写。如果要复制HashMap具有嵌套结构的 a,HashMap.putAll()将按引用复制,因为它不知道如何准确复制您的对象。例如:

import java.util.*;
class Playground {
    public static void main(String[ ] args) {
        Map<Integer, Map<Integer,List<Float>>> dataA = new HashMap<>();
        Map<Integer, Map<Integer,List<Float>>> dataB = new HashMap<>();

        dataA.put(1, new HashMap<>());
        dataB.putAll(dataA);

        assert(dataB.get(1).size() == 0);

        dataA.get(1).put(2, new ArrayList<>());

        if (dataB.get(1).size() == 1) { // true
            System.out.println(
                "Sorry object reference was copied - not the values");
        }
    }
}

所以基本上你需要像这里一样自己复制字段

List <Float> aX = new ArrayList<>(accelerometerReadingsX);
List <Float> aY = new ArrayList<>(accelerometerReadingsY);

List <Float> gX = new ArrayList<>(gyroscopeReadingsX);
List <Float> gY = new ArrayList<>(gyroscopeReadingsY);

Map<Integer, Map<Integer, Float>> readings = new HashMap<>();

Map<Integer,List<Float>> accelerometerReadings = new HashMap<>();
accelerometerReadings.put(X_axis, aX);
accelerometerReadings.put(Y_axis, aY);
readings.put(Sensor.TYPE_ACCELEROMETER, accelerometerReadings);

Map<Integer,List<Float>> gyroscopeReadings = new HashMap<>();
gyroscopeReadings.put(X_axis, gX);
gyroscopeReadings.put(Y_axis, gY);
readings.put(Sensor.TYPE_GYROSCOPE, gyroscopeReadings);
于 2016-02-08T09:24:26.563 回答
5

如果我们想在 Java 中复制一个对象,我们需要考虑两种可能性:浅拷贝深拷贝

浅拷贝是我们只复制字段值的方法。因此,副本可能依赖于原始对象。在深度复制方法中,我们确保树中的所有对象都被深度复制,因此副本不依赖于任何可能会更改的早期现有对象。

这个问题是对深拷贝方法应用的完美定义。

首先,如果您有一个简单的HashMap<Integer, List<T>>地图,那么我们只需创建一个这样的解决方法。创建List<T>.

public static <T> HashMap<Integer, List<T>> deepCopyWorkAround(HashMap<Integer, List<T>> original)
{
    HashMap<Integer, List<T>> copy = new HashMap<>();
    for (Map.Entry<Integer, List<T>> entry : original.entrySet()) {
        copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    return copy;
}

这个使用Stream.collect()方法创建克隆地图,但使用与前一种方法相同的想法。

public static <T> Map<Integer, List<T>> deepCopyStreamWorkAround(Map<Integer, List<T>> original)
{
    return original
            .entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey, valueMapper -> new ArrayList<>(valueMapper.getValue())));
}   

但是,如果里面的实例T也是可变对象,我们就有大问题了。在这种情况下,真正的深拷贝是解决此问题的替代方案。它的优点是至少对象图中的每个可变对象都是递归复制的。由于副本不依赖于之前创建的任何可变对象,因此不会像我们在浅副本中看到的那样意外修改它。

为了解决这个问题,这个深拷贝实现将完成这项工作。

public class DeepClone
{
    public static void main(String[] args)
    {
        Map<Long, Item> itemMap = Stream.of(
                entry(0L, new Item(2558584)),
                entry(1L, new Item(254243232)),
                entry(2L, new Item(986786)),
                entry(3L, new Item(672542)),
                entry(4L, new Item(4846)),
                entry(5L, new Item(76867467)),
                entry(6L, new Item(986786)),
                entry(7L, new Item(7969768)),
                entry(8L, new Item(68868486)),
                entry(9L, new Item(923)),
                entry(10L, new Item(986786)),
                entry(11L, new Item(549768)),
                entry(12L, new Item(796168)),
                entry(13L, new Item(868421)),
                entry(14L, new Item(923)),
                entry(15L, new Item(986786)),
                entry(16L, new Item(549768)),
                entry(17L, new Item(4846)),
                entry(18L, new Item(4846)),
                entry(19L, new Item(76867467)),
                entry(20L, new Item(986786)),
                entry(21L, new Item(7969768)),
                entry(22L, new Item(923)),
                entry(23L, new Item(4846)),
                entry(24L, new Item(986786)),
                entry(25L, new Item(549768))
        ).collect(entriesToMap());


        Map<Long, Item> clone = DeepClone.deepClone(itemMap);
        clone.remove(1L);
        clone.remove(2L);

        System.out.println(itemMap);
        System.out.println(clone);
    }

    private DeepClone() {}

    public static <T> T deepClone(final T input)
    {
        if (input == null) return null;

        if (input instanceof Map<?, ?>) {
            return (T) deepCloneMap((Map<?, ?>) input);
        } else if (input instanceof Collection<?>) {
            return (T) deepCloneCollection((Collection<?>) input);
        } else if (input instanceof Object[]) {
            return (T) deepCloneObjectArray((Object[]) input);
        } else if (input.getClass().isArray()) {
            return (T) clonePrimitiveArray((Object) input);
        }

        return input;
    }

    private static Object clonePrimitiveArray(final Object input)
    {
        final int length = Array.getLength(input);
        final Object output = Array.newInstance(input.getClass().getComponentType(), length);
        System.arraycopy(input, 0, output, 0, length);
        return output;
    }

    private static <E> E[] deepCloneObjectArray(final E[] input)
    {
        final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length);
        for (int i = 0; i < input.length; i++) {
            clone[i] = deepClone(input[i]);
        }

        return clone;
    }

    private static <E> Collection<E> deepCloneCollection(final Collection<E> input)
    {
        Collection<E> clone;
        if (input instanceof LinkedList<?>) {
            clone = new LinkedList<>();
        } else if (input instanceof SortedSet<?>) {
            clone = new TreeSet<>();
        } else if (input instanceof Set) {
            clone = new HashSet<>();
        } else {
            clone = new ArrayList<>();
        }

        for (E item : input) {
            clone.add(deepClone(item));
        }

        return clone;
    }

    private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map)
    {
        Map<K, V> clone;
        if (map instanceof LinkedHashMap<?, ?>) {
            clone = new LinkedHashMap<>();
        } else if (map instanceof TreeMap<?, ?>) {
            clone = new TreeMap<>();
        } else {
            clone = new HashMap<>();
        }

        for (Map.Entry<K, V> entry : map.entrySet()) {
            clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
        }

        return clone;
    }
}
于 2019-05-23T09:52:12.857 回答
5

从 Java 10 开始可以使用

Map.copyOf

用于创建一个浅拷贝,它也是不可变的。(这是它的Javadoc)。对于深层副本,如本答案中所述,您需要某种值映射器来制作值的安全副本。不过,您不需要复制密钥,因为它们必须是不可变的。

于 2019-06-27T09:05:16.857 回答
4

在 Java 中,当您编写时:

Object objectA = new Object();
Object objectB = objectA;

objectA并且objectB是相同的并且指向相同的引用。改变一个会改变另一个。因此,如果您更改objectA(而不是其引用)的状态,objectB也将反映该更改。

但是,如果你写:

objectA = new Object()

ThenobjectB仍然指向您创建的第一个对象( original objectA),而objectA现在指向一个新对象。

于 2012-04-09T20:24:27.943 回答
1

由于这个问题仍然没有答案,而且我遇到了类似的问题,我会尝试回答这个问题。问题(正如其他人已经提到的)是您只是将引用复制到同一个对象,因此对副本的修改也会修改原始对象。所以你要做的是复制对象(你的地图值)本身。最简单的方法是让所有对象都实现可序列化接口。然后序列化和反序列化您的地图以获得真实副本。您可以自己执行此操作,也可以使用您可以在此处找到的 apache commons SerializationUtils#clone(): https ://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/ lang/SerializationUtils.html但请注意,这是最简单的方法,但序列化和反序列化大量对象是一项昂贵的任务。

于 2014-11-17T08:46:27.163 回答
0

您将一个对象分配给另一个对象,您所做的只是复制对该对象的引用,而不是它的内容。您需要做的是获取对象 B 并手动将对象 A 的内容复制到其中。

如果您经常这样做,您可能会考虑clone()在类上实现一个方法,该方法将创建一个相同类型的新对象,并将其所有内容复制到新对象中。

于 2012-04-09T20:30:07.990 回答
0

由于 OP 已经提到他无法访问其中存在 HashMap 的基类 - 恐怕只有很少的选项可用。

在 Java 中执行对象的深层复制的一种(非常缓慢且资源密集的)方法是滥用许多类有意或无意扩展的“可序列化”接口,然后利用它来将您的类序列化为 ByteStream。反序列化后,您将拥有相关对象的深层副本。

可以在此处找到此指南:https ://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

于 2019-03-04T16:39:57.290 回答
0

Java supports shallow(not deep) copy concept

You can archive it using:

  • constructor
  • clone()
  • putAll()
于 2020-08-03T14:53:40.083 回答