#java #collections #hashmap
#java #Коллекции #hashmap
Вопрос:
Как мне протестировать / профилировать реализацию hashCode () в Java? т. Е. Распределяет ли она мои тестовые данные достаточно равномерно и т.д.? Есть ли какой-либо простой грубый способ в самом java API?
Ответ №1:
Map<Integer, Integer> hashCodes = new HashMap<Integer, Integer>();
for (YourHashcodedClass testData: largeCollectionOfTestData) {
Integer hashCode = Integer.valueOf(testData.hashCode());
Integer occurrences = hashCodes.get(hashCode);
if (occurrences == null) {
occurrences = 0;
}
hashCodes.put(hashCode, occurrences 1);
}
Затем проанализируйте вашу карту на предмет коллизий.
Комментарии:
1. карта содержит ваши хэш-коды. любая запись с вхождениями > 1 является конфликтной.
Ответ №2:
Честно говоря, вам не нужно профилировать или тестировать распространение вашего hashCode()
метода, если вы следуете лучшим практикам. Смотрите приведенный ниже рецепт хэш-кода из Эффективной Java. Более того, даже если вы не слишком хорошо ее написали, HashMap
реализация перефразирует ваш результат, чтобы уменьшить коллизии:
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);
}
Вы также можете использовать HashCodeBuilder
из Apache Commons Lang для создания хэш-кода для вас.
Эффективный рецепт хэш-кода Java 2nd Edition
- Сохраните некоторое постоянное ненулевое значение, скажем 17, в
int
переменной с именемresult
. - Вычислите
int
hashcodec
для каждого поля:- Если поле является
boolean
, вычислите(f ? 1 : 0)
- Если поле является
byte, char, short, int
, вычислите(int) f
- Если поле является
long
, вычислите(int) (f ^ (f >>> 32))
- Если поле является
float
, вычислитеFloat.floatToIntBits(f)
- Если поле является a
double
, вычислитеDouble.doubleToLongBits(f)
, затем хэшируйте полученный результатlong
, как указано выше. - Если поле является ссылкой на объект и
equals
метод этого класса сравнивает поле путем рекурсивного вызоваequals
, выполните рекурсивный вызовhashCode
для поля. Если значение поля равноnull
, верните 0. - Если поле представляет собой массив, обрабатывайте его так, как если бы каждый элемент был отдельным полем. Если каждый элемент в поле массива значим, вы можете использовать один из
Arrays.hashCode
методов, добавленных в версии 1.5.
- Если поле является
- Объедините хэш-код
c
вresult
следующим образом:result = 31 * result c;