Try English version of Quizful



Раздаем бесплатные Q! подробности в группе Quizful.Alpha-test
Топ контрибуторов
loading
loading
Знаете ли Вы, что

Лучшие IT работодатели регулярно просматривают рейтинги и профили пользователей в поисках кандидатов. Для корректного отображения ваших данных рекомендуем заполнить ваш профиль и добавить информацию о вас и вашей профессии.

Лента обновлений
ссылка 14:04:08
Комментарий от coven:
а почему разные маски? разве у второго ПК не долдна быть т...
ссылка 12:42:02
Комментарий от zyurii:
Вибачаюсь за свого співвітчизника. І погоджуюсь з Вашим т...
ссылка Jul 21 23:10
Комментарий от KlimAndr:
если бы речь шла об одной акции и 99 споров и вопросов ...
ссылка Jul 21 22:36
Комментарий от KlimAndr:
? по первым двум буквам , видно,что три младшие линии ...
ссылка Jul 21 21:46
Комментарий от KlimAndr:
мне понравилось.+
Статистика

Тестов: 153, вопросов: 8599. Пройдено: 411050 / 2001593.

Использование Map в Java

head tail Статья
категория
Java
дата07.06.2012
авторKvanGee
голосов30

Использование Map в Java

Множество представляет собой набор данных, в котором можно быстро найти существующий элемент. Однако для этого нужно иметь точную копию требуемого элемента. Этот вид поиска не очень распространен, поскольку обычно известна лишь некоторая информация (ключ), по которой можно найти соответствующий элемент. Специально для этого предназначена структура данных,поддерживающая отображение, которую называют также картой. Карта хранит пары "ключ-значение". Каждое значение можно найти по его ключу. Например, в таблице могут находиться записи с информацией о сотрудниках, где ключами являются идентификационные номера сотрудников, а значениями — объекты Employee.

Интерфейс Map (java.util.Map<K, V>)

  1. Vget(KeyK) – Возвращает объект, соответствующий указанному ключу или значение null, если карта не содержит указанный ключ. Ключ может быть равен null.
  2. Vput(KeyK, ValueV) – Добавляет ключ и значение к карте. Если такой ключ уже имеется, то новый объект заменяет предыдущий, связанный с этим ключом. Этот метод возвраща­ет предыдущее значение объекта или значение null, если ключ не содержался в карте ранее. Ключ может быть равен null, но значение должно быть отлично от null.
  3. voidputAll(Map<? extendsK, ? extendsV> entries) – Добавляет все элементы заданной карты к текущей.
  4. booleancontainsKey(Objectkey) – Возвращает значение true, если в карте имеется указанный ключ.
  5. booleancontainsValue(Objectvalue) – Возвращает значение true, если в карте имеется указанное значение.
  6. Set<Map.Entry<K, V>> entrySet() – Возвращает представление карты в виде множества объектов Map.Entry, т.е. пар "ключ-значение". Из этого представления можно удалять элементы, при этом они удаляются и из карты, но добавлять их нельзя.
  7. Set<K> keySet() – Возвращает представление карты в виде множества всех ключей. Из этого представления можно удалять элементы, при этом ключи и соответствующие им значения автоматически удаляются из карты, но добавлять новые элементы нельзя.
  8. Collection<V> values() – Возвращает представление карты в виде множества всех значений. Из этого представления можно удалять элементы, при этом значения и соответствующие им ключи автоматически удаляются из карты, но добавлять новые элементы нельзя.

Основные реализации Map

В библиотеке Java предусмотрено две основные реализации карт: хэш-карта HashMap и карта-дерево ТгееМар. Оба класса реализуют интерфейс Map.
В хэш-карте ключи расположены случайным образом, а в карте-дереве — в строгом порядке. Хэш-функция, или функция сравнения, применяется только для ключей, а са­ми значения, соответствующие этим ключам, не хэшируются и не сравниваются.
Какую же из карт следует выбрать? Как и для множеств, хэширование несколько быстрее, поэтому его рекомендуется использовать там, где порядок следования клю­чей не имеет значения.

Ниже показано, как создается хэш-карта для хранения информации о сотрудниках.

Map staff = new HashMap< String, Employee>();
//HashMap реализует интерфейс Map
Employee harry = new Employee(“Harry Hacker”);
staff.put(“987-98-9996”, harry);

При добавлении объекта к карте должен быть указан и его ключ. В данном случае ключом является строка, а соответствующим значением — объект Employee.
Чтобы обратиться к объекту, нужно воспользоваться ключом.


String s = “987-98-9996”;
Employee e = staff.get(s);//читает запись harry

Если данных, соответствующих указанному ключу в наборе данных нет, метод get() возвращает значение null. Ключи должны быть уникальными: нельзя сохранить два значения с одинаковым ключом. Если вызвать метод put() дважды с одинаковым ключом, то второе значение просто заменит первое. Кроме того, метод put() возвращает предыдущее значение, хранимое с указанным ключом.

Метод remove() удаляет элемент из карты, а метод size() возвращает число элементов карты.

В архитектуре наборов данных карта сама по себе не рассматривается как набор. (В других архитектурах структур данных карта считается набором пар, или значений, индексируемых ключами.) Однако в библиотеке Java предусмотрено использованиепредставления (view) карты, которое реализует интерфейс Collection или один из его дочерних интерфейсов.

Существует три типа представлений: в виде множества ключей, набора значений (который не является множеством) или множества пар "ключ-значение". Ключи и пары "ключ-значение" формируют множество, так как в карте может присутствовать только один уникальный экземпляр объекта-ключа. Перечисленные ниже методы возвращают эти три типа представлений карты.


Set keySet()
Collection values()
Set> entrySet()

(Элементы последнего множества пар "ключ-значение" являются объектами внутреннего класса Map.Entry) Обратите внимание, что множество ключей не является объектом HashSet или TreeSet,но представляет собой объект некоторого другого класса, реализующего интерфейс Set.Интерфейс Set расширяет интерфейс Collection.Следовательно, вы можете использовать метод keySet().
Например, можно перебрать все ключи карты:


Set keys = map.keySet();
for (String key: keys) {
//действия с ключом
}

Если нужно одновременно просматривать ключи и значения, то можно избежать необходимости поиска значений, перечисляя всезаписи. Для этого можно использовать следующую заготовку кода:


for (Map.Entry entry: staff.entrySet()) {
String key = entry.getKey();
Employee value = entry.getValue();
//действия с ключом и значением
}

Специальные реализации Map

Хэш-карты с нестрогим кэшированием

Класс хэш-карт с нестрогим кэшированием WeakHashMap был разработан для ре­шения интересной задачи. Что происходит со значением, ключ которого больше не используется в программе, например из-за того, что исчезла последняя ссылка на этот ключ? В этом случае обратиться к объекту-значению уже нельзя. А так как этот ключ уже не содержится нигде в программе, то нет никакой возможности удалить его пару "ключ-значение" из карты. Но почему его не может удалить система сборки мусора, в обязанности которой как раз и входит удаление неиспользуемых объектов?

К сожалению, все не так просто. Средство сборки мусора в системе управления памятью следит за действующими объектами. Пока объект карты активен,все ячейки карты также активны. Таким образом, об удалении неиспользуемых значений из ак­тивных карт должна позаботиться сама программа. Именно для этого и предназначен класс WeakHashMap, Такая структура данных взаимодействует с системой сборки му­сора для удаления тех пар "ключ-значение", для которых единственной ссылкой на ключ является запись в хэш-таблице.

Вот как работает этот механизм. Класс WeakHashMap использует для хранения ключей нестрогие ссылки (weak references). ОбъектWeakReference содержит ссылку на другой объект, т.е. в данном случае на ключ хэш-таблицы. Обычно, если при сборке мусора выясняется, что на некоторый объект нет ссылок, этот объект удаляется. А еслиединственная ссылка на объект имеет типWeakReference, эта нестрогая ссылка помещается в очередь. Периоди­чески происходит проверка на появление новых ссылок в очереди, так как это означает, что данный ключ больше не используется и его объект можно удалить. Таким образом, классWeakHashMap удаляет соответствующее этому ключу значение.

Связанные хэш-карты

В JDK 1.4 были предложены классы LinkedHashSet и LinkedHashMap, которые запоминают последовательность вставки в набор данных новых пунктов. Таким обра­зом, порядок следования пунктов таблицы уже не выглядит случайным. По мере добавления записей в таблицу они формируют двусвязный список.
Рассмотрим, например, карту:


Map staff = new LinkedHashMap();
Staff.put(“144-25-5464”, new Employee(“Amy Lee”));
Staff.put(“567-24-2546”, new Employee(“Harry Hacker”));
Staff.put(“157-62-7935”, new Employee(“Gary Cooper”));
Staff.put(“456-62-5527”, new Employee(“Francesca Cruz”));

Итератор staff.ketSet().iterator() перечислит ее ключи в следующем порядке:

144-25-5464
567-24-2546
157-62-7935
456-62-5527

А итератор staff.values().iterator() перечислит ее значения так:

Amy Lee
Harry Hacker
Gary Cooper
Francesca Cruz

Связная хэш-карта может запоминать порядок доступа и учитывать его при пере­боре элементов. Каждый раз, когда вы вызываете метод get() или put() запись, которую он затрагивает, удаляется из занимаемой позиции и перемещается в конец связного списка. При этих операциях изменяется структура связного списка, но не ячеек хэш-таблицы. Запись остается в той ячейке, которая соответствует хэш-коду ключа. Для того чтобы создать подобную хэш-карту, нужно использовать следующее выражение:


LinkedHashMap<k, v="">(initialCapacity, loadFactor, true)

Знать порядок доступа необходимо, например, для создания кэша, работающего по принципу "последнего по времени использования". Например, вам может понадо­биться хранить в памяти наиболее часто используемые записи, а те, с которыми приходится работать редко, извлекать из базы данных. Если вы не находите запись в таб­лице, а таблица уже достаточно заполнена, вы можете удалить с помощью итератора первые несколько элементов. Именно эти элементы используются реже других.

Хэш-карты с индивидуальным хэшированнием

В JDK 1.4 добавлен еще один специальный класс IdentityHashMap, выполняю­щий индивидуальное хэширование. Хэш-коды ключей в нем подсчитываются не мето­дом hashCode(),а методом System.identityHashCode().Этот метод вычисляет хэш-код по адресу объекта в памяти. Кроме того, для сравнения объектов класс IdentityHashMapприменяет оператор ==, а не метод equals().

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

Использование Collections в Map

Немодифицируемые представления

Класс Collectionsсодержит методы, которые создаютнемодифицируемые пред-ставления (unmodifiableview) наборов данных. В этих представлениях реализована проверка существующего набора, выполняемая на этапе работы программы. При по¬пытке модифицировать набор, генерируется исключение и набор данных остается неизменным.
Для получения немодифицируемых Map представлений используются методы:


Collections.unmodifiableMap
Collections.unmodifiableSortedMap

Предположим, например, что вы хотите, чтобы некоторый фрагмент вашего кода просматривал, но не затрагивал содержимое набора данных. Для этого выполните следующие действия:


Map<String, Employee> staff = new HashMap<String, Employee>();
…
lookAt(new Collections.unmodifiableMap(staff));

МетодCollections.unmodifiableMap возвращает экземпляр класса, реализующего интерфейс Map. Метод доступа этого класса извлекает значения из набора staff.Очевидно, что метод lookAt() может вызывать все методы, объявленные в интерфейсе Map. Однако все модифицирующие методы пере¬определены так, что вместо обращения к базовому набору генерируют исключение UnsupportedOperationException.

Немодифицирующее представление не делает сам набор данных неизменяемым. Вы можете модифицировать набор посредством обычной ссылки (в наше случае это staff).При этом методы, модифицирующие элементы набора, остаются доступными.

Синхронизируемые представления

Если вы обращаетесь к набору данных из нескольких потоков, необходимо при¬нять меры, чтобы не повредить информацию в наборе. Это неминуемо произойдет, если, например, один поток будут пытаться включить элемент в хэш-таблицу, а другой — перегенерировать ее.

Вместо того чтобы реализовать классы наборов данных, обеспечивающих безопасную работу с потоками, разработчики библиотеки предпочли использовать для этого механизм представлений. Например, статический метод synchronizedMap() классаCollectionsможет преобразовать любую карту в Map с синхронизированны¬ми методами доступа.


HashMap<String, Employee> hashMap = new HashMap<String, Employee>();
Map<String, Employee> map = Collections.synchronizedMap(hashMap);

Теперь вы можете обращаться к объекту map из различных потоков. Такие методы, как get() и put(),сериализованы: каждый метод должен полностью закончить свою работу перед тем, как другой поток сможет вызвать подобный метод.

При разработке программы необходимо следить, чтобы ни один поток не обращался к структуре данных посредством обычных де синхронизированных методов. Самый простой способ обеспечить это — не сохранять ни одной ссылки на базовый объект.

Классы Hashtable и Dictionary

Традиционный класс Hashtable служит той же цели, что и HashMap, и имеет, в сущности, такой же интерфейс. Как и методы класса Vector, методы класс Hashtable синхронизированы. Если Вам не требуется обеспечить синхронизацию или совместимость с кодом для предыдущих версий платформы Java, то в таком случае следует воспользоваться классом HashMap. Класс Dictionary является абстрактным классом-родителем Hashtable.

Если Вам понравилась статья, проголосуйте за нее

Голосов: 30  loading...
aprel1234   Geniy   epfl   zxcvbn91   dmitrykr   katch   Mr_X   Amagister   c0nst   krasavello13   Koraxion   newpavel   polinkot   dimon_lvov   kirya_ua   vorotnikovdv   fanshtorm   bal_gena   SamTan   Igat   daimond   LuxCore   ig_gor   SerhiyBs   CraneCreator   Vanadij1   ProBY   engineer77721   Str1kerTT   Alibek7000