Тестирование / профилирование функции хэш-кода для java hashmap

#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 hashcode c для каждого поля:
    • Если поле является 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;