Копирование HashMap в Java

Я пытаюсь сохранить временный контейнер класса, содержащего элемент:

HashMap<Integer,myObject> myobjectHashMap

Класс, называемый myobjectsList

Тогда я делаю

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

затем: добавьте некоторые элементы hashmap в (like2)

затем

myobjectListB = myobjectListA; //B has 2

затем: Добавить элементы hashmap в A; (например, еще 4)

затем верните A в элементы, хранящиеся в B;

myobjectListA = myobjectListb;

но когда я делаю это, B растет с A, а я добавляю элементы hashmap в A. Теперь у него 6 предметов, потому что у B было 6.

Я хочу, чтобы у A было оригинальное 2 до конца после последнего экзамена в С++ я бы использовал копию с объектами, что эквивалентно java?

Добавлено: ОК. Я ничего не объяснил, объясняя это. MyObjectsList не содержит HashMap, он получен из класса MyBaseOjbectsList, у которого есть член HashMap, а MyObjectsList расширяет MyBaseOjbectsList. Это имеет значение.?

Ответ 1

Если вам нужна копия HashMap, вам нужно построить новую.

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

Это создаст (неглубокую) копию карты.

Ответ 2

Вы также можете использовать

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

Ответ 3

Разница в том, что в C++ ваш объект находится в стеке, тогда как в Java ваш объект находится в куче. Если A и B являются объектами, в любое время в Java вы делаете:

B = A

A и B указывают на один и тот же объект, поэтому все, что вы делаете с A, вы делаете с B и наоборот.

Используйте новый HashMap() если вы хотите два разных объекта.

И вы можете использовать Map.putAll(...) для копирования данных между двумя картами.

Ответ 4

Здесь есть небольшое (ОГРОМНОЕ) занижение. Если вы хотите скопировать 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);

Ответ 5

В Java, когда вы пишете:

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

objectA и objectB совпадают и указывают на одну и ту же ссылку. Изменение одного изменит другое. Поэтому, если вы измените состояние objectA (а не его ссылку), objectB также отразит это изменение.

Однако, если вы пишете:

objectA = new Object()

Затем objectB все еще указывает на первый созданный вами объект (оригинал objectA), а objectA теперь указывает на новый объект.

Ответ 6

Поскольку этот вопрос все еще остается без ответа, и у меня была аналогичная проблема, я постараюсь ответить на это. Проблема (как уже упоминалось ранее) заключается в том, что вы просто копируете ссылки на один и тот же объект, и, таким образом, модификация на копии также изменит исходный объект. Итак, вам нужно скопировать объект (ваше значение карты). Самый простой способ сделать это - сделать все ваши объекты реализацией сериализуемого интерфейса. Затем выполните сериализацию и десериализацию карты, чтобы получить реальную копию. Вы можете сделать это самостоятельно или использовать apache commons SerializationUtils # clone(), который вы можете найти здесь: https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SerializationUtils.html Но имейте в виду, что это простейший подход, но дорого стоит задача сериализации и десериализации множества объектов.

Ответ 7

Если мы хотим скопировать объект в 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;
    }
}

Ответ 8

Что вы назначаете одному объекту другому, все, что вы делаете, это копирование ссылки на объект, а не его содержимое. Вам нужно сделать свой объект B и вручную скопировать содержимое объекта A в него.

Если вы это часто делаете, вы можете рассмотреть возможность применения метода clone() в классе, который будет создавать новый объект того же типа, и скопировать все его содержимое в новый объект.

Ответ 9

Поскольку ОП упоминал, что у него нет доступа к базовому классу, внутри которого существует HashMap - я боюсь, что вариантов очень мало.

Один (мучительно медленный и ресурсоемкий) способ выполнения глубокой копии объекта в Java - использовать интерфейс Serializable, который многие классы намеренно - или непреднамеренно расширяют, - и затем использовать его для сериализации вашего класса в ByteStream. После десериализации у вас будет глубокая копия рассматриваемого объекта.

Руководство по этому вопросу можно найти здесь: https://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html.

Ответ 10

Начиная с Java 10 можно использовать

Map.copyOf

для создания мелкой копии, которая также является неизменной. (Вот его Javadoc). Для глубокой копии, как упомянуто в этом ответе, вам нужен какой-то тип сопоставителя значений, чтобы сделать безопасную копию значений. Вам не нужно копировать ключи, поскольку они должны быть неизменными.