Создать хеш из строки и int - PullRequest
11 голосов
/ 31 июля 2009

Я помню, затмение и идея иметь этот шаблон для автоматического создания hashCode объекта на основе его атрибутов.

Одна из стратегий, если используется число и строка, выглядит примерно так:

  return stringValue.hashCode() + intValue * 32;

или что-то подобное.

У меня нет ни затмения, ни идеи, и я бы хотел создать такую ​​функцию.

EDIT

На основе ответов я создаю этот мини-класс

    class StringInt {
        private final String s;
        private final int i;

        static StringInt valueOf( String string , int value ) {
            return new StringInt( string, value );
        }
        private StringInt( String string, int value ) {
            this.s = string;
            this.i = value;
        }
        public boolean equals( Object o ) {
            if( o != null && o instanceof StringInt ){
                StringInt other = ( StringInt ) o;
                return this.s == other.s && this.i == other.i;
            }

            return false;
        }
        public int hashCode() {
            return s != null ? s.hashCode() * 37 + i : i;
        }
    }

Этот класс должен использоваться в качестве ключа для большой карты памяти (> 10 тыс. Элементов). Я не хочу повторять их каждый раз, чтобы определить, совпадают ли String и int.

Спасибо.

пс .. ммх, наверное, это должны быть имена StringIntKey.

Ответы [ 6 ]

8 голосов
/ 31 июля 2009

Используйте Apache Commons HashcodeBuilder:

public int hashCode() {
    new HashCodeBuilder(17, 37).
           append(myString).
           append(myInt);
}

Ссылка здесь: http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html

А здесь:

http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx

3 голосов
/ 31 июля 2009

Eclipse всегда выполняет примерно одну и ту же хеш-функцию, вот пример для класса с полями in и String в качестве полей

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.interger;
        result = prime * result + ((this.string == null) ? 0 : this.string.hashCode());
        return result;
    }

Они всегда выбирают 31 как простое число, а затем умножают на встроенные хэш-функции или значение, если это примитив. Нечто подобное не составит труда создать как метод.

     public int hashCode(Object ... things) {
         final int prime = 31;
         int result = 1;
         for(Object thing : things) {
             result = prime * result + thing.hashCode();
         }
         return result;
     }
2 голосов
/ 31 июля 2009

Или, если вы не хотите добавлять другую библиотеку, сделайте что-то вроде следующего:

public int hashCode() {
    StringBuilder builder = new StringBuilder();
    builder.append(myString);
    builder.append(myInteger);
    return builder.toString().hashCode();
}
1 голос
/ 20 февраля 2017

Вы также можете использовать Objects класс из пакета java.util.Objects для быстрого получения хеш-кода.

@Override
public int hashCode() {
    return Objects.hash(this.string, this.integerValue, this.otherDataTypes);
}
1 голос
/ 31 июля 2009

Метод хеш-кода - это то, что потенциально может быть вызвано много раз, и поэтому его стоит оптимизировать. Если расчет сложен, рассмотрите возможность запоминания значения хеша. Кроме того, избегайте действий, которые влекут за собой больше вычислений, чем необходимо. (Например, решение StringBuilder тратит большую часть своего времени на создание временной строки.)

Еще одна вещь, на которую я хочу обратить внимание, это то, что качество хэша важно. Вы хотите избежать любого алгоритма хеширования, который отображает множество общих ключей. Если это произойдет, поиск в хэш-таблице может перестать быть O (1). (В худшем случае это будет O (N) ... то есть эквивалентно линейному поиску!). Вот пример плохой хеш-функции:

int hashcode() {
    int hash = 1;
    for (int val : this.values) {
        hash = hash * value;
    }
    return hash;
}

Рассмотрим, что произойдет, если элемент this.values равен нулю ...

0 голосов
/ 31 июля 2009

В дополнение к вашему последнему редактированию, если скорость извлечения важнее, чем проблемы хранения, вы можете предварительно вычислить и сохранить хеш-код при создании класса StringInt. Это безопасно, поскольку вы пометили поля String и int как final, а также учитывая, что String является неизменным.

Кроме того, вы можете оптимизировать свой метод equals, проверив, что сравниваемый объект == this перед выполнением полного сравнения. Я бы также порекомендовал сначала сделать сравнение на основе более дешевых int, прежде чем сравнивать строковые поля.

Еще одно последнее предложение: вы можете изменить метод valueOf(String, int), чтобы создать StringInt или вернуть ранее созданный экземпляр, если он уже существует с такими же значениями String и int. Это делает строительство более дорогим, но сравнение очень дешевым, поскольку вы можете сравнивать StringInt s, используя "==", зная, что никогда не будут созданы два StringInt s с одинаковыми значениями String и int.

...