2013-11-17 2 views
0

Я создаю составной ключ для хэш-карты в java и хочу определить собственный хэш-код для каждого из этих объектов. Мой вопрос в том, что является лучшей методологией двух ниже. Мой составной ключ имеет три атрибута String и один атрибут int.Лучший способ создания хеш-функции

public int hashCode(){ 
    return (className + methodName + uniqueNumber).hashCode(); 
} 

public int hashCode(){ 
    return (className + methodName + desc + uniqueNumber).hashCode(); 
} 

я должен иметь Classname, имяМетод и уникальный номер, чтобы гарантировать, что каждый ключ имеет уникальный хэш-код. Я хочу пойти с методом, который дает меньше шансов на столкновение. Моя интуиция заключается в том, что чем больше атрибутов, которые я «добавляю» к моей хэш-карте, тем меньше вероятность столкновения. Однако я не совсем уверен, что это правильно.

+0

Я считаю, что существует много подобных вопросов на SO .... –

+2

Если вы хотите гарантировать отсутствие столкновений, 'return uniqueNumber;' –

+1

uniqueNumber - это последовательно увеличивающееся число, значения которого у меня нет прямого управления. Использование только uniqueNumber будет генерировать уникальное значение хэша, но я потеряю способность ссылаться на определенные значения в моем hashmap – HXSP1947

ответ

2

Ваш вопрос немного неясен, какие поля вам нужны/достаточны, чтобы однозначно различать ключ.

Как правило, вы должны комбинировать отдельные хеши (в составном ключе) путем умножения на простые коэффициенты.

Предполагая, первый пример:

public int hashCode() { 
    int h = className.hashCode() * 23; 
    h += methodName.hashCode() * 17; 
    h += uniqueNumber; 
    return h; 
} 

Ото, если uniqueNumber на самом деле уникальный, можно упростить:

public int hashCode() {return uniqueNumber;} 

В вашем комментарии вы упомянули одну вещь: «Использование только uniqueNumber будет генерировать уникальный хэш, но я потеряю способность ссылаться на определенные значения в моем хэшмапе ».

Теперь это очень важно: «Идентификация экземпляра» - это совсем другая вещь для хеша на & lookup, от «Value»! Вы не можете использовать тот же хэш-код & карты для обоих.

Например, если вам нужен ключ (ИмяКласс, MethodName) -> SomeValue поиск, что бы «значение» поиск & нужен будет хэширование по ИмяКлассу & значений имяМетода так, что он может быть повторен: то есть, так вы можете создать ключ для Map.get() для выполнения поиска.

«Идентификация экземпляра» на самом деле имеет встроенную поддержку для хэширования & карт на Java - это называется IdentityHashMap.

Но в большинстве случаев, в том числе & особенно составных ключей которые предположительно будет использоваться для карты, ключевые потребности, чтобы иметь возможность быть реконструировано позже выполнить поиск. Таким образом, ключ должен иметь значение семантики, и сомнительно, должен ли ваш uniqueNumber быть частью ключа.

Когда вы переходите к поиску позже, как вы получите правильный uniqueNumber для извлечения данных? У меня такое ощущение, что:

  1. Либо должен быть первый класс объект там вместо этого, который можно использовать в качестве ключа непосредственно (так не требуется класс CompositeKey больше), или что

  2. Вы не может повторно получить uniqueNumber, и в этом случае он не работает/не требуется в любом случае.

Резюмируя: если uniqueNumber действительно необходимо или это применимо вообще, я бы ожидать, что она уже воплощен в первый класс объекта. Это не так. Похоже, вы, вероятно, должны использовать ключ на основе значений и сбросить бит uniqueNumber (отсюда как минимум).

Так что моя рекомендация:

public int hashCode() { 
    int h = className.hashCode() * 23; 
    h += methodName.hashCode() * 17; 
    h += desc.hashCode(); 
    return h; 
} 

Позвольте мне знать, если это помогает.

+0

правильный. Я не привел лучший пример. Чтобы упростить мой вопрос, использует ли больше атрибутов объекта для вычисления хеш-кода, уменьшает вероятность столкновений – HXSP1947

+0

№. Когда у вас достаточно полей для формирования «первичного ключа» или «уникального ключа», умножайте их на разные простые факторы, у вас будет разумный хэш-код с низкой столкновением. Для составного ключа на основе значений достаточно «className» и «methodName» было бы достаточно и правильно. –

+0

Это помогает. uniqueNumber используется для вычисления другого значения, и я думал, что включение его в мою функцию уменьшит вероятность столкновения, но у меня нет способа восстановить это число позже. Однако className и methodName не являются уникальными для ключа. Часть проблемы здесь заключается в том, что я полностью уничтожил объяснение моей проблемы.Я не использую uniqueNumber в моем методе equals, так как я не могу его восстановить, но я использую desc, поскольку desc with className и methodName создает уникальный ключ. Я упоминал className, methodName и uniqueNumber как ключ – HXSP1947

0

Несколько комментариев;

(1) Для хэш-кодов не обязательно быть уникальным. Фактически, они, как правило, НЕ гарантированно являются уникальными. В большинстве случаев было бы слишком дорогостоящим вычислительным способом гарантировать уникальность и не было бы желательным. Столкновения не катастрофичны.

(2) Хэш-коды должны отражать состояние экземпляра объекта, а не класса объекта. Такие вещи, как имя класса, не будут входить в него. Если, конечно, это IS - данные экземпляра класса, например, в классе, который представляет собой один кадр трассировки стека.

(3) Хороший хеш-код будет иметь большое количество возможных значений, и эти значения будут распределены вероятностно таким образом, чтобы столкновения были НЕВЫПОЛНЕННЫ.

(4) В Java хэш-код должен соответствовать Object.equals(). См. Javadoc для java.lang.Object для справки.

+0

className - это атрибут моего ключа (я использую ASM), поэтому className важен для дифференцирования ключей. Мой вопрос заключается в том, позволяет ли использовать больше значений для вычисления хеш-кода, что снижает вероятность столкновения или не делает существенной разницы. – HXSP1947

+0

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

+0

Использование большего количества значений снижает вероятность столкновения, если они не являются избыточными. Я также согласен с Томасом, что вы, вероятно, захотите использовать как className, так и methodName. Все остальное, вероятно, не намного лучше. –

Смежные вопросы