Я пытался ограничить размер новой карты, которую я создавал с помощью метода Google Maps.newHashMapWithExpectedSize(n) в качестве (незначительной) пространственной оптимизации, так как я знал, сколько записей ключевого значения он будет содержать. Вместо того, чтобы вставлять каждую из новых пар ключ-значение в свой собственный ковш, произошло столкновение, и моя первая пара ключ-значение была перезаписана, несмотря на то, что два ключа были разными значениями. Мои ключи были объектами String и n = 3. Два ключа, которые хэшировали в том же ведре, были "records" и "pageSize".
Когда я изменил код, чтобы просто использовать Maps.newHashMap(), поведение было как и ожидалось, хотя оно создало неиспользуемое пространство в структуре данных. Мое предположение, без погружения в фактический код, заключается в том, что ограничение размера HashMap просто приводит к большей вероятности столкновений, хотя я бы подумал, что основная структура данных будет обрабатывать это немного более изящно. Поэтому мои вопросы:
Вы уверены, что здесь указали всю информацию? Здесь интерактивный сеанс Scala, который показывает, что вы пытаетесь сделать:
scala> val map = com.google.common.collect.Maps.newHashMapWithExpectedSize[String, String](3)
map: java.util.HashMap[String,String] = {}
scala> map.put("pageSize", "foo")
res1: String = null
scala> map.put("records", "bar")
res2: String = null
scala> map.put("third", "3")
res3: String = null
scala> map.put("fourth", "4")
res4: String = null
scala> map.toString()
res5: String = {pageSize=foo, fourth=4, records=bar, third=3}
Как вы можете видеть, экземпляр, возвращаемый этим методом, представляет собой java.util.HashMap
; вы можете добавить больше, чем количество запрошенных элементов; и столкновения обрабатываются просто отлично.
Фактически, если вы посмотрите на источник, этот метод является просто оболочкой вокруг конструктора HashMap.
Независимо от того, будут ли два ключа хешировать в одном и том же ведре, зависит от комбинации хэш-кода hashCode()
для каждого и количества ведер (плюс алгоритм, используемый для сопоставления хэш-кодов с кодами, очевидно).
Вполне возможно, что два ключа имеют хэш в том же самом ковше для почти любого размера таблицы. Столкновения являются естественными в хэш-таблицах. Цель состоит в том, чтобы обеспечить минимальное среднее количество записей в каждом ковше относительно общего количества записей. Большая хеш-таблица уменьшает вероятность столкновений за счет большего пространства.
Следует избегать newHashMapWithExpectedSize (n) при использовании небольших значений для n?
Нет, не совсем. Действительно ли факт, что у вас столкновение является проблемой?
После вставки "записей" в карту, если бы я вызвал map.hasKey("pageSize"), я бы понял?
Если и только если вы добавили запись с ключом "pageSize". Хеширование в одно и то же ведро не влияет на поведение карты. Несколько записей могут храниться в каждом ведре, и только если найден ключ, равный параметру "pageSize", hasKey
возвращает true.
поскольку я знал, сколько записей с ключевыми значениями он будет содержать
Можете ли вы использовать ImmutableMap
вместо этого? Часто, когда вы заранее знаете, сколько записей будет содержать карта, она должна быть неизменной. Поскольку ImmutableMap
знает, что количество содержащихся в нем записей никогда не изменится, возможно, он будет оптимизировать свой размер лучше, чем измененный HashMap
. Не говоря уже о других преимуществах неизменности.
HashMap
не перезаписывает один ключ другим ключом, независимо от того, как он создан. Период. Должно быть что-то еще, и вам нужно предоставить SSCCE, который продемонстрирует вашу проблему, если мы хотим помочь вам разобраться с этим.