web-dev-qa-db-ja.com

JavaのHashMapのコピー

メンバーを含むクラスの一時コンテナを保持しようとしています:

HashMap<Integer,myObject> myobjectHashMap

MyobjectsListというクラス

それから

myojbectsListA = new myojbectsList();
myojbectsListB = new myobjectsList();

次に:ハッシュマップアイテムをAに追加します(like2)

それから

myobjectListB = myobjectListA; //B has 2

その後:ハッシュマップアイテムをAに追加します。 (さらに4つなど)

次に、AをBに格納されているアイテムに返します。

myobjectListA = myobjectListb;

しかし、これを行うと、ハッシュマップアイテムをAに追加しているときにBがAとともに成長します。

AにC++での最後の割り当ての後、元の2がまだ残っているようにします。オブジェクトでコピーを使用します。Javaと同等のものは何ですか?

追加:OKこれについて説明することを省略しました。MyObjectsListにはHashMapが含まれていません。これは、HashMapメンバーを持つMyBaseOjbectsListクラスから派生し、MyObjectsListはMyBaseOjbectsListを拡張します。これは違いを生みますか?

104
user691305

HashMapのコピーが必要な場合は、新しいものを作成する必要があります。

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

これにより、マップの(浅い)コピーが作成されます。

212
ratchet freak

使用することもできます

clone()

あるハッシュマップから別のハッシュマップにすべての要素をコピーする方法

あるハッシュマップから別のハッシュマップにすべての要素をコピーするためのプログラム

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

14
user2236292

違いは、C++ではオブジェクトがスタック上にあるのに対して、Javaではオブジェクトがヒープ内にあることです。 AとBがオブジェクトの場合、Javaでいつでも実行できます。

B = A

AとBは同じオブジェクトを指しているため、Aに対して行うことはすべてBに対して行い、その逆も同様です。

2つの異なるオブジェクトが必要な場合は、新しいHashMap()を使用します。

また、Map.putAll(...)を使用して、2つのマップ間でデータをコピーできます。

11
ControlAltDel

ここには小さな(巨大な)控えめな表現があります。ネストされた構造を持つHashMapをコピーする場合、オブジェクトを正確にコピーする方法がわからないため、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);
6
murt

Javaでは、次のように記述します。

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

objectAobjectBは同じで、同じ参照を指します。一方を変更すると、他方も変更されます。したがって、objectAの状態(その参照ではない)を変更すると、objectBもその変更を反映します。

ただし、次の場合:

objectA = new Object()

その後、objectBはまだ作成した最初のオブジェクト(元のobjectA)を指していますが、objectAは新しいオブジェクトを指しています。

4
assylias

この質問にはまだ回答がなく、同様の問題があったので、これに答えようとします。問題(すでに他の人が述べたように)は、同じオブジェクトへの参照をコピーするだけであるため、コピーの変更によってOriginオブジェクトも変更されるということです。そのため、オブジェクト(マップ値)自体をコピーする必要があります。これを行う最も簡単な方法は、すべてのオブジェクトにシリアル化可能なインターフェイスを実装することです。次に、マップをシリアライズおよびデシリアライズして、実際のコピーを取得します。これは自分で行うことも、ここにあるApache commons SerializationUtils#clone()を使用することもできます。 https://commons.Apache.org/proper/commons-lang/javadocs/api-2.6/org/ Apache/commons/lang/SerializationUtils.html ただし、これは最も簡単なアプローチですが、多くのオブジェクトをシリアライズおよびデシリアライズするのは費用のかかる作業であることに注意してください。

2
KIC

Javaでオブジェクトをコピーする場合、考慮する必要がある2つの可能性があります:浅いコピー深いコピー

shallow copyは、フィールド値のみをコピーする場合のアプローチです。したがって、コピーは元のオブジェクトに依存する場合があります。 deep copyアプローチでは、ツリー内のすべてのオブジェクトが深くコピーされるようにします。したがって、コピーは、変更される可能性のある以前の既存のオブジェクトに依存しません。

この質問は、ディープコピーアプローチのアプリケーションの完全な定義です。

最初に、単純な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内のインスタンスもmutable objectsである場合、大きな問題があります。この場合、実際のディープコピーは、この問題を解決する代替手段です。その利点は、オブジェクトグラフ内の少なくとも各mutable objectが再帰的にコピーされることです。コピーは以前に作成されたmutable objectに依存しないため、浅いコピーで見たように偶然に変更されることはありません。

このディープコピー実装が作業を行うことを解決します。

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;
    }
}
2
Teocci

Java 10以降は使用可能です

Map.copyOf

shallow copyを作成しますが、これも不変です。 (ここに Javadoc )があります。 deep copyの場合、この answer yo で述べたように、値の安全なコピーを作成するために何らかの値マッパーが必要です。ただし、keysimmutableでなければならないため、コピーする必要はありません。

0
xuesheng

OPはHashMapが内部に存在する基本クラスにアクセスできないと述べているので、利用できるオプションはほとんどないのではないかと思います。

Javaでオブジェクトのディープコピーを実行する1つの(痛みを伴う低速でリソース集約的な)方法の1つは、多くのクラスが意図的に(または意図せずに拡張して)シリアル化するインターフェイスを悪用し、これを使用してシリアル化することですByteStreamのクラス。逆シリアル化すると、問題のオブジェクトの詳細コピーが作成されます。

このためのガイドはここにあります: https://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

0
Felteh

あるオブジェクトを別のオブジェクトに割り当てるのは、referenceをその内容ではなくオブジェクトにコピーすることだけです。必要なのは、オブジェクトBを取得し、オブジェクトAの内容を手動でコピーすることです。

これを頻繁に行う場合は、クラスにclone()メソッドを実装して、同じタイプの新しいオブジェクトを作成し、その内容をすべて新しいオブジェクトにコピーすることを検討してください。

0
zigdon