Java: использовать hashCode () внутри equals () для удобства? - PullRequest
17 голосов
/ 14 сентября 2011

Рассмотрим следующий тестовый пример, является ли плохой практикой использование метода hashCode () внутри equals в качестве удобного ярлыка?

public class Test 
{    
    public static void main(String[] args){
        Test t1 = new Test(1, 2.0, 3, new Integer(4));
        Test t2 = new Test(1, 2.0, 3, new Integer(4));
        System.out.println(t1.hashCode() + "\r\n"+t2.hashCode());
        System.out.println("t1.equals(t2) ? "+ t1.equals(t2));
    }

    private int myInt;
    private double myDouble;
    private long myLong;
    private Integer myIntObj;

    public Test(int i, double d, long l, Integer intObj ){
        this.myInt = i;
        this.myDouble = d;
        this.myLong = l;
        this.myIntObj = intObj;
    }

    @Override
    public boolean equals(Object other)
    {        
        if(other == null) return false;
        if (getClass() != other.getClass()) return false;            

        return this.hashCode() == ((Test)other).hashCode();//Convenient shortcut?
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 53 * hash + this.myInt;
        hash = 53 * hash + (int) (Double.doubleToLongBits(this.myDouble) ^ (Double.doubleToLongBits(this.myDouble) >>> 32));
        hash = 53 * hash + (int) (this.myLong ^ (this.myLong >>> 32));
        hash = 53 * hash + (this.myIntObj != null ? this.myIntObj.hashCode() : 0);
        return hash;
    }   
}

Вывод из основного метода:

1097562307
1097562307
t1.equals(t2) ? true

Ответы [ 7 ]

41 голосов
/ 14 сентября 2011

В общем, сравнивать hashCode () совсем не безопасно, а не использовать equals (). Когда equals () возвращает false, hashCode () может вернуть то же значение в соответствии с контрактом hashCode () .

16 голосов
/ 14 сентября 2011

Очень плохо! Равенство HashCode не означает, что equals возвращает true. Контракт заключается в том, что два равных объекта должны иметь одинаковый hashCode. Но он НЕ утверждает, что два объекта с одинаковым HashCode должны быть равны.

7 голосов
/ 14 сентября 2011

Как и во всех других ответах, это плохая практика. Однако , одна из ситуаций, когда вы можете обратиться к хеш-коду в методе equals, - это случаи, когда у вас есть неизменяемый объект и ранее кэшировал хеш-код . Это позволяет выполнить дешевое неточное сравнение перед выполнением полного сравнения. Например:

public class MyImmutable {
    private final String a;
    private final String b;
    private final int c;

    private int hashCode;

    public MyImmutable(String a, String b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        MyImmutable that = (MyImmutable) o;

        // Compare cached hashCodes first before performing more expensive comparison.
        return hashCode == that.hashCode() && c == that.c && !(a != null ? !a.equals(that.a) : that.a != null) && !(b != null ? !b.equals(that.b) : that.b != null);
    }

    @Override
    public int hashCode() {
        if (hashCode == 0) {
            // hashCode not cached, or it was computed as 0 (we recalculate it in this case).
            hashCode = a != null ? a.hashCode() : 0;
            hashCode = 31 * hashCode + (b != null ? b.hashCode() : 0);
            hashCode = 31 * hashCode + c;
        }

        return hashCode;
    }
}
6 голосов
/ 14 сентября 2011

Это , а не ОК. Хеш-коды по своей природе не гарантируют, что они будут уникальными.

5 голосов
/ 14 сентября 2011

Плохая практика? Более того, это совершенно неправильно. Два неравных объекта могут возвращать один и тот же хэш-код. Не делай этого.

3 голосов
/ 14 сентября 2011

Как говорит Райан Стюарт , ваш написанный код неисправен.

Ситуация, в которой может быть полезно использовать хеш-код ваших объектов в equals(), - это когдаваш объект кэширует хеш-коды, а определение равенства порождено дорого.В этом случае вы можете использовать равенство кэшированных хеш-кодов в качестве одной из ранних необходимых, но недостаточных проверок на равенство, чтобы быстро вернуть false для большинства пар объектов, которые не equals().

3 голосов
/ 14 сентября 2011

Вот контракт, скопированный из спецификации объекта [JavaSE6]:

Не требуется, чтобы два объекта были неравными в соответствии с метод equals (Object), затем вызов метода hashCode для каждого из два объекта должны давать разные целочисленные результаты. Тем не менее программист должен знать, что выдаёт разные целочисленные результаты для неравных объектов возможно повышение производительности хеш-таблиц.

Чтобы ответить на ваш вопрос, нет. Не очень хорошая идея.

...