2010-03-01 6 views
93

Как я понимаю, есть несколько способов (возможно, другие, а) создать неглубокую копию Map в Java:Малая копия карты в 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(); 
} 

ответ

98

Всегда лучше копировать, используя конструктор копирования. clone() в Java не работает (см. SO: How to properly override clone method?).

Josh Bloch on Design - Copy Constructor versus Cloning

Если вы читали пункт о клонировании в моей книге, особенно если вы читаете между строк, вы будете знать, что я думаю, что clone глубоко сломана. [...] Жаль, что Cloneable сломан, но это происходит.

Блох (который, кстати, разработаны и внедрены в основу коллекции) даже пошел дальше, говоря, что он только обеспечивает clone() метод просто «потому, что люди ожидают его». Он НЕ рекомендует вообще его использовать.


Я думаю, что более интересная дискуссия, является ли конструктор копирования лучше, чем копия фабрики, но это другое обсуждение в целом.

+2

Хороший ответ, спасибо. – dcp

+0

Да, это одна из моих любимых частей книги. – polygenelubricants

+1

Я не люблю говорить, что clone() сломан. Я предпочитаю говорить, что клон был ужасным дизайнерским решением и может нанести вам вред, если вы не используете его должным образом.Кроме того, вы, возможно, никогда не доверяете другим методам clone(). Таким образом, мы в итоге похожи, стараемся избегать этого, но это не сломано. – santiagobasulto

49

Ни одно из двух: в constructor, что вы ссылаетесь определяется для HashMap реализации Map, (а также для других), но не для самого интерфейса карты (например, рассмотреть вопрос о Provider реализации из Интерфейс карты: вы не найдете этот конструктор).

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

В отношении интерфейса карты (и вашего вопроса, в котором вы спрашиваете, как скопировать карту, а не 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', которую вы используете, имеет конструктор копирования или нет. Таким образом, простой экземпляр-конструктор любой реализации «Карта» является избыточным. –

+1

Несомненно, хотя в целом мне нравятся 1-лайнеры лучше, чем 2-лайнеры. ;) –

7

Копировать карту, не зная ее реализации:

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

Рассмотрите возможность добавления параметров '' для обеспечения безопасности типа. – Barett

+0

Что относительно карт без конструкторов с нулевым аргументом? –