Как получить неизменяемую коллекцию из java HashMap?

Мне нужно получить коллекцию из java HashMap без изменений в карте, отражающихся в коллекции позже. Я хотел использовать Collection.toArray () для этого, но он не работает. Результирующий Object [] также изменяется (в javadocs сказано, что возвращенный массив будет «безопасным», поскольку эта коллекция не поддерживает никаких ссылок на него). Любой простой способ добиться этого?


person sanre6    schedule 28.01.2012    source источник
comment
Я не совсем понял, чего вы пытаетесь достичь. Но действительно ли LinkedHashMap то, что вы ищете?   -  person batbaatar    schedule 28.01.2012
comment
Нет .. порядок вставки - это не то, что я ищу. допустим, у нас есть HashMap ‹имя, лицо›. Hashmap.values ​​() вернет мне коллекцию ‹person›. Теперь любые изменения в HashMap отражаются и в этой коллекции, что является поведением по умолчанию. Но мне нужна фиксированная коллекция, в которой любые изменения на карте не будут отраженный   -  person sanre6    schedule 28.01.2012
comment
@ sanre6 Вы имеете в виду случайные изменения элементов (объектов), содержащих HashMap?   -  person    schedule 28.01.2012


Ответы (5)


Это невозможно сделать с помощью одного вызова API, вам нужно использовать глубокое клонирование. Клоны не будут изменены, когда вы внесете изменения в оригинал. Эта тема ранее обсуждалась на SO, см. Как клонировать ArrayList а также клонировать его содержимое? и Рекомендации утилиты глубокого клонирования.

person Bhesh Gurung    schedule 28.01.2012
comment
Я думаю, что этот ответ можно было бы расширить: что подразумевается под глубоким клоном и как это предотвращает модификации или общие ссылки? Ссылка может быть полезна ... - person ; 28.01.2012
comment
Cloner api сделал всю работу за меня. Спасибо за ссылки - person sanre6; 30.01.2012

Неизменяемая карта коллекций Google может помочь тебе.

см. Collections.unmodifiableMap также

person Balaswamy Vaddeman    schedule 28.01.2012
comment
Однако это ничего не говорит о изменчивости содержащихся объектов. - person ; 28.01.2012
comment
Я считаю, что неизменяемая карта коллекций Google - это то, что ищет OP. @pst: Читая документацию, я полагаю, что объекты, содержащиеся в com.google.common.collect.ImmutableMap, неизменяемы. - person Justin Muller; 28.01.2012
comment
мое понимание тоже такое же - person Balaswamy Vaddeman; 28.01.2012
comment
@JustinMuller Я не верю, что это толкование правильное. В нем ничего не говорится о неизменности K (единственный способ добиться этого в Java - добавить копию / клон объектов типа K). Он утверждает, что он отличается от unmodifiableMap, который вызовет исключение put, но по-прежнему будет показывать новые ключи через keys (например), если исходная (резервная) карта модифицирован; в документации звучит так, будто это разница. - person ; 28.01.2012
comment
То есть подумайте, если бы unmodifiableMap вместо этого назывался readonlyViewOfMap. - person ; 28.01.2012
comment
Если исходная резервная карта изменена (например, через put), то копия ImmutableMap не будет отражать новые изменения. (Если K представляет изменяемый тип, вы уже делаете что-то ужасно, ужасно неправильно.) - person Louis Wasserman; 28.01.2012
comment
Обратите внимание, что этот ответ ссылается на проект google-collections, который был заброшен более 2 лет назад. См. guava-libraries.googlecode.com. - person Kevin Bourrillion; 29.01.2012

Вы можете создать неизменяемый Карта

person Justin Muller    schedule 28.01.2012
comment
Однако это ничего не говорит о изменчивости содержащихся объектов. - person ; 28.01.2012
comment
Не говоря уже о том, что изменения в исходной карте отражаются в копии. - person Perception; 28.01.2012
comment
Я считаю, что Джастин прав. метод unmodifiableMap вернет доступное только для чтения представление карты, которое отразит любые изменения в базовом контейнере, а sanre6 не указал, что содержащиеся объекты должны быть неизменяемыми, только то, что карта должна быть. - person Francois; 28.01.2012

Следующее по-прежнему актуально и описывает наблюдаемую проблему (см. Бит о том, какой тип копирования выполняется). Однако я не отвечаю на вопрос, как выполнять глубокое копирование.

Вместо этого мое предложение состоит в том, чтобы проектировать объекты так, чтобы они были неизменяемыми , что полностью устраняет эту проблему. По моему опыту, это очень хорошо работает для большинства тривиальных объектов (то есть объектов, которые не являются «контейнерами») и может упростить код и рассуждения по этому поводу.


Из документации Javadoc для _1 _ :

Возвращает представление коллекции значений, содержащихся на этой карте. Коллекция поддерживается картой, поэтому изменения на карте отражаются в коллекции, и наоборот ...

Может быть, было бы полезно создать его копию?

HashMap<K,V> map = ....;
List<V> values = new ArrayList<V>(map.values());

Это, по сути, выполняет мелкую копию, которая «теперь отделена». Однако, будучи неглубокой копией, клонирование / копирование содержащихся объектов не выполняется. (См. Ответ βнɛƨн Ǥʋяʋиɢ, если требуется семантика глубокой копии: сам вопрос кажется немного расплывчато по этому поводу.)

Удачного кодирования

person Community    schedule 28.01.2012
comment
я сделал то же самое, это не работает. Изменения отражаются и в новом Списке. - person sanre6; 28.01.2012
comment
@ sanre6 Под изменениями вы подразумеваете изменения объектов в коллекции? (В отличие от изменений в коллекции.) Если да, просмотрите ссылки на мелкие / глубокие копии, которые объясняют наблюдаемое поведение, и ответ от βнɛƨн Ǥʋяʋиɢ. - person ; 28.01.2012
comment
да, точно меняет содержащиеся в нем объекты - person sanre6; 28.01.2012
comment
@ sanre6 Смотрите ссылки. И тогда ответ βнɛƨн Ǥʋяʋиɢ. :-) - person ; 28.01.2012
comment
так что я должен делать это на своем собственном горьком опыте;) - person sanre6; 28.01.2012
comment
@ sanre6 Я бы лично сделал сам объект неизменяемым по контракту. Удаление изменяемости объектов может полностью свести на нет такие проблемы: копия не требуется, потому что вы не можете ее изменить. Это работает очень хорошо для простых объектов. - person ; 28.01.2012

Создайте неглубокую копию исходной карты с HashMap.clone(), затем извлеките из нее коллекцию значений. Это создаст новые ссылки на объекты исходной карты во время вызова clone(); очевидно, что изменения внутри самих содержащихся объектов по-прежнему будут отражаться в скопированной коллекции. Если вы хотите такого поведения, единственный способ - это скопировать объекты карты в желаемую коллекцию на бумажном носителе.

person guido    schedule 28.01.2012