Вы спросили: «Или я что-то упустил? Пожалуйста, просветите меня».
Да, вы что-то упустили.
Внутри реализации класса HashMap он защищает от плохих функций хеширования:
/**
* Applies a supplemental hash function to a given hashCode, which
* defends against poor quality hash functions. This is critical
* because HashMap uses power-of-two length hash tables, that
* otherwise encounter collisions for hashCodes that do not differ
* in lower bits. Note: Null keys always map to hash 0, thus index 0.
*/
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
Итак, ваши результирующие хеш-коды в вашем примере:
k1 - Before: 3366 After: 3566
k2 - Before: 3367 After: 3567
k3 - Before: 3368 After: 3552
Таким образом, даже при небольшом размере выборки из трех элементов один из них был перефразирован. Теперь он не защищает от агрессивно злых хеш-кодов (return randomInt();
или return 4;
просто не может быть защищен от), но он защищает от плохо написанных хеш-кодов.
Я должен также отметить, что вы можете многое изменить, используя нетривиальные входные данные. Рассмотрим, например, следующие строки.
k1longer - Before: 1237990607 After: 1304548342
k2longer - Before: 2125494288 After: 2040627866
k3longer - Before: -1281969327 After: -1178377711
Обратите внимание, насколько различны младшие биты: единственные вещи, которые имеют значение для хеш-кода, - это младшие биты. Размер резервной карты всегда является степенью двойки. Это действительно задокументировано в коде:
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
Перефразировка делает довольно приличную работу, чтобы убедиться, что старшие биты (которые обычно игнорируются в хэш-таблице) по-прежнему влияют на младшие биты. Вот отображение исходных позиций хеш-кода и воздействующих на них битов:
00: 00000000000000000000000000000001
01: 00000000000000000000000000000010
02: 00000000000000000000000000000100
03: 00000000000000000000000000001000
04: 00000000000000000000000000010001
05: 00000000000000000000000000100010
06: 00000000000000000000000001000100
07: 00000000000000000000000010001001
08: 00000000000000000000000100010010
09: 00000000000000000000001000100100
10: 00000000000000000000010001001000
11: 00000000000000000000100010010000
12: 00000000000000000001000100100001
13: 00000000000000000010001001000010
14: 00000000000000000100010010000100
15: 00000000000000001000100100001000
16: 00000000000000010001001000010001
17: 00000000000000100010010000100010
18: 00000000000001000100100001000100
19: 00000000000010001001000010001001
20: 00000000000100010010000100010011
21: 00000000001000100100001000100110
22: 00000000010001001000010001001100
23: 00000000100010010000100010011000 # means a 1 in the 23rd bit position will
24: 00000001000100100001000100110001 # cause positions 4, 5, 8, 12, and 20 to
25: 00000010001001000010001001100010 # also be altered
26: 00000100010010000100010011000100
27: 00001000100100001000100110001001
28: 00010001001000010001001100010010
29: 00100010010000100010011000100100
30: 01000100100001000100110001001000
31: 10001001000010001001100010010000
Итак, вы беспокоитесь о том, чтобы "уменьшить время поиска больших O с O (1) до ... кто знает, насколько плохо ... может быть хуже, чем O (log n)" и "Не будет ли Sun предоставить значение по умолчанию функция hashCode, которая будет хорошо работать для больших наборов данных? " может быть остановлен - у них есть меры предосторожности для предотвращения этого.
Если это поможет вам хоть немного успокоиться, вот теги автора для этого класса. Они буквально все звезды в мире Java. (комментарии с # мои)
* @author Doug Lea # Formerly a Java Community Process Executive Committee member
* @author Josh Bloch # Chief Java architect at Google, amongst other things
* @author Arthur van Hoff # Done too many hardcore Java things to list...
* @author Neal Gafter # Now a lead on the C# team at Microsoft, used to be team lead on javac