2012-02-03 4 views
5

У меня есть простой пользовательский класс Point следующим образом, и я хотел бы знать, может ли быть реализована моя реализация hashCode, или если это лучшее, что она получит.Java hashCode для класса Point

public class Point 
{ 
    private final int x, y; 

    public Point(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public int getX() 
    { 
     return x; 
    } 

    public int getY() 
    { 
     return y; 
    } 

    @Override 
    public boolean equals(Object other) 
    { 
     if (this == other) 
      return true; 

     if (!(other instanceof Point)) 
      return false; 

     Point otherPoint = (Point) other; 
     return otherPoint.x == x && otherPoint.y == y; 
    } 


    @Override 
    public int hashCode() 
    { 
     return (Integer.toString(x) + "," + Integer.toString(y)).hashCode(); 
    } 

} 
+1

Как вы пытаетесь улучшить его? Вы хотите попытаться сделать это быстрее? – David

+0

Вы хотите гарантировать уникальность? скорость? – Adrian

+0

Я хотел бы гарантировать оба :) –

ответ

8

Пожалуйста, не используйте строки. За этим и несколькими реализациями существует много теории (метод разделения, умножение и т. Д.). Если у вас есть около часа вы можете смотреть этот MIT-Class

Это, как говорится, вот что Netbeans 7.1 предлагает:

@Override 
public int hashCode() { 
    int hash = 7; 
    hash = 71 * hash + this.x; 
    hash = 71 * hash + this.y; 
    return hash; 
} 

октября 2015 Редактировать

Я начал использовать IntelliJ некоторое время назад, Теперь я счастлив. Это то, что создает автоматическое генерирование hashCode. Это немного меньше подробностей. Обратите внимание на использование простых чисел.

+0

+1 Интересно, что Netbeans предлагает нечто отличное от затмения, но основа для реализации аналогична и прочная. – nybbler

+0

Я смущен, как вторая реализация - хорошая реализация? Вы получаете столкновения даже с очень маленькими числами, например (0,31), (1,0). Это кажется очень вредным, нет? –

+0

@ChristopherShroba yours - очень интересный комментарий, и я рассмотрю, как только вернусь из отпуска! Основная проблема заключается в том, что 'result' инициализируется' 0' с учетом вашего ввода образца. Тем не менее, это то, что делает IntelliJ 2016 ... – Gevorg

0

Я использовал, чтобы написать свой собственный хэш и равна функции, то я нашел это:)

import org.apache.commons.lang.builder.HashCodeBuilder; 
import org.apache.commons.lang.builder.EqualsBuilder; 

@Override 
public boolean equals(Object obj) { 
    return EqualsBuilder.reflectionEquals(this, obj); 
} 
@Override 
public int hashCode() { 
    return HashCodeBuilder.reflectionHashCode(this); 
} 

конечно иметь в виду следующее:

Поскольку отражение включает типы, динамически разрешены, не удается выполнить определенные оптимизации виртуальной машины Java. Следовательно, светоотражающие операции имеют более низкую производительность, чем их отражающие эквиваленты, и их следует избегать в разделах кода , которые часто используются в приложениях с высокой чувствительностью к характеристикам. SRC

+0

Поскольку есть только два поля, вы также можете использовать эту библиотеку, но явно укажите поля. –

+0

Если этот класс используется значительно в коллекции, отражающий хэш-код будет большим хитом производительности. – user949300

+1

Я бы рекомендовал использовать ['HashCodeBuilder.append'] (http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/builder/HashCodeBuilder.html#append%28int%29). –

2

Я бы рекомендовал использовать более простой и более производительный метод без струн, возможно, метод Джоша Блохи из this answer, в вашем случае просто:

return 37 * x + y; 

EDIT: nybbler правильно. Что на самом деле рекомендуется есть:

int result = 373; // Constant can vary, but should be prime 
result = 37 * result + x; 
result = 37 * result + y; 
+1

Это не совсем то, что рекомендуется в вашем ответном ответе. Вы пропустили, что это должно быть сделано для каждого поля ** отдельно **, но не в одно и то же время. Этот алгоритм генерирует тот же результат для [0,37] и [1,0] – nybbler

+0

Обратите внимание, что новая реализация по-прежнему будет генерировать столкновение для любой пары точек в форме (x, 37y), (y, 37x) .. . – Gevorg

0

От класса Направьте JDK (в унаследованы от Point2d):

public int hashCode() { 
    long bits = java.lang.Double.doubleToLongBits(getX()); 
    bits ^= java.lang.Double.doubleToLongBits(getY()) * 31; 
    return (((int) bits)^((int) (bits >> 32))); 
} 

Это выглядит немного лучше, чем осуществление.

0

Вы можете посмотреть в существующие реализации типа точка классов:

/** 
343  * Returns the hashcode for this <code>Point2D</code>. 
344  * @return a hash code for this <code>Point2D</code>. 
345  */ 
346  public int hashCode() { 
347  long bits = java.lang.Double.doubleToLongBits(getX()); 
348  bits ^= java.lang.Double.doubleToLongBits(getY()) * 31; 
349  return (((int) bits)^((int) (bits >> 32))); 
350  } 

от: http://kickjava.com/src/java/awt/geom/Point2D.java.htm#ixzz1lMCZCCZw

Простое руководство для реализации Hashcode можно найти here

+0

Слово предупреждения всем, кто использует это для идентификации. Конфликты хэшей реальны ... например. pastebin.com/6wM3W3Wv – vincent

0

По умолчанию, Eclipse будет использовать hashCode() для вашего класса Point, аналогичного:

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + getOuterType().hashCode(); 
    result = prime * result + x; 
    result = prime * result + y; 
    return result; 
} 

По крайней мере, включение простого числа в ваш алгоритм hashCode поможет с его «уникальностью».

+0

Возможно, вы неправильно использовали «Java» вместо «Eclipse». По умолчанию «hashCode» обычно реализуется путем преобразования внутреннего адреса объекта в целое число ». –

+0

@MatthewFlaschen Действительно, я это сделал. Обновлено сейчас; спасибо, что поймали это. – nybbler

5

Ручное умножение значений всех значимых полей элементов, предложенных Геворгом, вероятно, является наиболее эффективным и имеет хорошее распределение значений. Однако, если вы предпочитаете читаемость, есть хорошие альтернативы доступны либо в Java 7 ...

import java.util.Objects; 

... 

@Override 
public int hashCode() { 
    return Objects.hash(x, y); 
} 

... или в Guava библиотеке:

import com.google.common.base.Objects; 

.... 

@Override 
public int hashCode() { 
    return Objects.hashCode(x, y); 
} 

Оба этих метода varags просто делегировать Arrays.hashCode(Object[] a), поэтому есть небольшое влияние на производительность из-за автобоксации int и создания массива ссылок на объекты, но оно должно быть гораздо менее значительным, чем использование рефлексии.

И читаемость просто замечательно, так как вы просто видите, какие поля используются для вычисления хэш-код и все множатся и добавить синтаксис просто скрыты под капотом Arrays.hashCode(Object[] a):

public static int hashCode(Object a[]) { 
    if (a == null) 
     return 0; 

    int result = 1; 

    for (Object element : a) 
     result = 31 * result + (element == null ? 0 : element.hashCode()); 

    return result; 
} 
+0

Все еще уязвим для любых пар в форме '(x, 31y), (y, 31x)', например. (0, 31), (1, 0) или (3, 217), (7, 93). Я пытаюсь объяснить здесь широкую дискуссию. Есть ли способ иметь более надежную реализацию или всего 2 целых числа, которым приходится иметь дело с такой проблемой (которая зависит от простого числа, используемого в генерации хэш-кода)? – Gevorg

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