Дрібна копія карти на Java


106

Як я розумію, існує декілька способів (можливо, і інших) для створення дрібної копії MapJava на Java:

Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy;

// first way
shallowCopy = new HashMap<String, Object>(data);

// second way
shallowCopy = (Map<String, Object>) ((HashMap<String, Object>) data).clone();

Чи є один із способів кращим перед іншим, і якщо так, то чому?

Одне, що варто згадати, - це те, що другий спосіб дає попередження "Неперевірений ролик". Тож вам доведеться додати, @SuppressWarnings("unchecked")щоб обійти його, що трохи дратує (див. Нижче).

@SuppressWarnings("unchecked")
public Map<String, Object> getDataAsMap() {
    // return a shallow copy of the data map
    return (Map<String, Object>) ((HashMap<String, Object>) data).clone();
}

У нових версіях Java (оскільки Java 10, якщо бути точним) ви можете використовувати статичний заводський метод Map.copyOf . Але зауважте, що вона повертає немодифіковану карту!
Олександр

Відповіді:


106

Завжди краще копіювати за допомогою конструктора копій. clone()у Java зламано (див. ТАК: Як правильно перекрити метод клонування? ).

Джош Блох про дизайн - конструктор копіювання проти клонування

Якщо ви прочитали предмет про клонування у моїй книзі, особливо якщо ви читаєте між рядків, то знатимете, що я думаю, що cloneце глибоко зламано. [...] Сором, що Cloneableпорушується, але трапляється.

Блох (який, до речі, розробив та впровадив рамки Колекції), навіть пішов далі, сказавши, що він пропонує clone()метод лише "тому, що люди цього очікують". Він насправді НЕ рекомендує використовувати його взагалі.


Я думаю, що більш цікавою дискусією є те, чи краще конструктор копій, ніж фабрика копій, але це взагалі інша дискусія.


1
Так, це одна з моїх улюблених частин книги.
полігенмастильні матеріали

1
Я не люблю говорити, що клон () зламаний. Я вважаю за краще сказати, що клон був жахливим дизайнерським рішенням і може завдати вам великої шкоди, якщо ви не використовуєте його належним чином. Крім того, ви ніколи не можете довіряти методам клонування () інших людей. Таким чином ми закінчуємо подібне, намагаємось уникати цього, але це не порушено.
santiagobasulto

4
Не використовуючи копіюючий копіювач, ви не повинні знати, яку реалізацію Map ви копіюєте? Схоже, зайве обмеження.
jon-hanson

"що він забезпечує лише метод clone () лише" тому, що люди цього очікують "" - джерело?
Адам Паркін

60

Ні те, ні два: конструктор , який ви маєте на увазі визначаються для HashMap реалізації карти , (як і для інших) , але не для карти інтерфейсу самого по собі (наприклад, розгляне Provider реалізацію інтерфейсу Map: ви не знайде цього конструктора).

З іншого боку, не доцільно використовувати clone()метод, як пояснив Джош Блок.

Стосовно інтерфейсу Map (і вашого питання, в якому ви запитуєте, як скопіювати Map, а не HashMap), ви повинні використовувати Map # putAll () :

Копіює всі відображення із зазначеної карти на цю карту (необов'язкова операція). Ефект цього виклику еквівалентний ефекту виклику put (k, v) на цій карті один раз для кожного відображення від ключа k до значення v вказаної карти.

Приклад:

// HashMap here, but it works for every implementation of the Map interface
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy = new HashMap<String, Object>();

shallowCopy.putAll(data);

2
Тоді для уточнення: якщо ви знаєте , що копіюєте, до реалізації Mapякої є конструктор копій, немає причин не використовувати конструктор копій тоді?
Адам Паркін

2
Саме так, і ви навіть можете подумати навпаки: якщо ви користуєтеся, putAllвам не потрібно знати, чи має Mapвикористовувана вами програма конструктора копій чи ні. Таким чином, лише конструктор копій будь-якої Mapреалізації є надлишковим.
Лука Фагіолі

1
Звичайно, хоча, як правило, я люблю 1-лайнери краще, ніж 2-лайнери. ;)
Адам Паркін

11

Скопіюйте карту, не знаючи її реалізації:

static final Map shallowCopy(final Map source) throws Exception {
    final Map newMap = source.getClass().newInstance();
    newMap.putAll(source);
    return newMap;
}

3
Потрібно додати <K,V>параметри типу, щоб забезпечити безпеку типу.
Баретт

1
Що з картами без конструкторів з нульовим аргументом?
Ісаак Саффолд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.