Руководство по Java WeakHashMap

В этом уроке мы изучим Java WeakHashMap и слабые ссылки с примерами. Также изучим различия между WeakHashMap и HashMap.

1. Введение в Java WeakHashMap

Класс WeakHashMap(присутствует в пакете java.util) представляет собой реализацию интерфейса Map на основе HashTable и присутствует с версии Java 1.2. Он имеет почти те же функции, что и HashMap, включая конструкторы, методы, производительность и внутреннюю реализацию.

Основное различие между HashMap и WeakHashMap заключается в том, что последний имеет слабые ключи. Запись в WeakHashMap будет автоматически удалена сборщиком мусора, если ключ не имеет сильных или слабых ссылок. Каждый ключевой объект в WeakHashMap хранится косвенно как референт слабой ссылки.

Обратите внимание, что объекты-значения в WeakHashMap удерживаются обычными сильными ссылками. Поэтому объекты-значения не должны строго ссылаться на свои собственные ключи, ни напрямую, ни косвенно, поскольку это предотвратит отбрасывание ключей.

Вколлекциях Java класс WeakHashMap объявлен следующим образом:

public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>

Как показано выше, он реализует интерфейс Map и расширяет класс AbstractMap.

Java WeakHashMap

2. Работа с WeakHashMap

2.1 Создание WeakHashMap

Мы можем создать WeakHashMap, используя следующие конструкторы:

  • WeakHashMap(): используется для создания пустой карты с начальной емкостью по умолчанию 16 и коэффициентом загрузки по умолчанию 0,75.
  • WeakHashMap(int initialCapacity): используется для создания пустой карты с заданной начальной емкостью и коэффициентом загрузки по умолчанию 0,75.
  • WeakHashMap(int initialCapacity, float loadFactor): используется для создания пустой карты с заданной начальной емкостью и заданным коэффициентом загрузки.
  • WeakHashMap(Map m): используется для создания нового WeakHashMap с теми же записями, что и указанная карта.
WeakHashMap<String, String> map = new WeakHashMap<>();WeakHashMap<String, String> map = new WeakHashMap<>(16);WeakHashMap<String, String> map = new WeakHashMap<>(16, 8);Map<String, String> map = new HashMap<String, String>() {{put("key1", "value1");put("key2", "value2");}};WeakHashMap<String, String> map = new WeakHashMap<>(map);

2.2 Методы WeakHashMap

Некоторые важные методы, представленные в классе WeakHashMap:

  • Объект put(ключ, значение): вставляет пару ключ-значение в карту.
  • Object get(key): возвращает значение для указанного ключа в карте.
  • boolean containsKey(key): возвращает значение true или false в зависимости от того, найден ли указанный ключ в карте или нет.
  • boolean containsValue(value): Подобно методу containsKey(), он ищет указанное значение вместо ключа.
  • Set keySet(): возвращает набор всех ключей, хранящихся в карте.
  • Set entrySet(): возвращает набор всех сопоставлений, сохраненных в карте.
  • Value remove(Object key): удаляет пару ключ-значение для указанного ключа.
  • int size(): возвращает размер карты, который равен количеству пар ключ-значение, хранящихся в карте.

2.3 Пример WeakHashMap

Давайте быстро рассмотрим пример создания WeakHashMap и то, как можно использовать описанные выше методы.

//Creating WeakHashMapWeakHashMap<Integer, String> map = new WeakHashMap<>();//Adding values to map using put()map.put(1, "A");map.put(2, "B");map.put(3, "C");System.out.println(map);//Getting a value from the mapString value = map.get(2);System.out.println(value);//Checking if a key or value present in the mapSystem.out.println(map.containsKey(3));System.out.println(map.containsValue("Z"));//Removing an entrymap.remove(3);System.out.println(map);//Finding map sizeSystem.out.println(map.size());//Iterating over the mapfor(Map.Entry<Integer, String> entry : map.entrySet()){System.out.println(entry.getKey() + " :: " + entry.getValue());}

3. Разница между HashMap и WeakHashMap

В Java ссылки на объекты могут быть многих типов. Давайте обсудим их, прежде чем углубляться в концепцию слабых ключей в WeakHashMap.

3.1. Сильные ссылки, мягкие ссылки и слабые ссылки

Сильные ссылки — это ссылки, которые мы создаем в обычной программе. Это простые назначения переменных. В данном примере переменная game имеет сильную ссылку на объект String со значением 'cricket'.

Любой объект, имеющий активную сильную ссылку, не подлежит сборке мусора.

 Игра в струны = «крикет»;

Мягкие ссылки объявляются явно. Объект, имеющий мягкую ссылку, не будет собран мусором, пока JVM не упадет с ошибкой OutOfMemoryError. JVM предпримет необходимые усилия, прежде чем освободить память, удерживаемую мягко ссылающимися объектами.

После того, как мы сделаем сильную ссылку нулевой, игровой объект будет доступен для сборки мусора, но будет собран только тогда, когда JVM действительно понадобится память.

// game is having a strong referenceString game = "cricket";// Wrapping a strong reference into a soft referenceSoftReference<String> softGame = new SoftReference<>(game);game = null; //Now it is eligible for GC 

Слабые ссылки также создаются явно и подвергаются немедленной сборке мусора при выполнении цикла GC. В случае слабых ссылок GC не будет ждать, пока ему понадобится память.

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

// strong referenceString game = "cricket";// Wrapping a strong reference in weak referenceWeakReference<String> softGame = new WeakReference<>(game);// Making the strong reference as nullgame = null; //GC can reclaim it any time

3.2. Поведение сборки мусора в WeakHashMap

Как упоминалось ранее, WeakHashMap хранит ключи как слабые ссылки. Поэтому при вызове GC его ключи подлежат сборке мусора.

В следующем примере мы сохраняем две записи в карте. И мы делаем один ключ нулевым. После запуска GC у нас должна быть только одна запись в карте.

Map<MapKey, String> map = new WeakHashMap<>();MapKey key1 = new MapKey("1");MapKey key2 = new MapKey("2");map.put(key1, "1");map.put(key2, "2");System.out.println(map);key1 = null; //Making it GC eligibleSystem.gc();Thread.sleep(10000);System.out.println(map);
 {MapKey{key='2'}=2, MapKey{key='1'}=1}{MapKey{key='2'}=2}

В WeakHashMap можно поместить нулевой ключ или нулевое значение. Сборщик мусора удаляет только ту запись из карты, для которой ссылка на ключ(т.е. объект) является нулевой. С другой стороны, сборщик мусора не удалит ключ со значением null из WeakHashMap.

4. Варианты использования WeakHashMap

Мы можем использовать WeakHapMap при создании простых кэшей или структур данных, подобных реестру, где мы хотим поместить объекты в виде пары ключ-значение. Когда запись удаляется из такого кэша, она больше не понадобится в приложении.

Это время от времени очищает наш кэш, удаляя неиспользуемые объекты из памяти, чтобы память не заполнялась анонимными объектами, которые мы больше не используем в нашем приложении.

5. Преобразование HashMap в WeakHashMap

Чтобы создать WeakHashMap из HashMap, мы можем использовать его конструктор new WeakHashMap(hashmap).

// Creating HashMapHashMap<Integer, String> hashMap = new HashMap<>();hashMap.put(1, "A");hashMap.put(2, "B");System.out.println("HashMap : " + hashMap);// Creating WeakHashMap from a HashMapWeakHashMap<Integer, String> weakHashMap = new WeakHashMap<>(hashMap);System.out.println("WeakHashMap : " + weakHashMap);
 HashMap: {1=A, 2=B}WeakHashMap: {2=B, 1=A}

6. Заключение

Вот и все о WeakHashMap в Java. Мы увидели, что это такое и чем оно отличается от HashMap.

Мы также рассмотрели практические примеры, включающие как HashMap, так и WeakHashMap, и то, как они ведут себя по-разному в отношении сборки мусора. Затем мы увидели различные типы ссылок, которые у нас есть, вместе с практическим вариантом использования для них в конце.

Исходный код на Github

Прокрутить вверх