Apache Commons HashCodeBuilder: ноль против нуля для типов Numeri c - PullRequest
0 голосов
/ 18 апреля 2020

Недавно я столкнулся со следующим сценарием "равенства" хеш-кодов в Java кодовой базе, использующей Apache Commons Lang 3, и был удивлен, что не смог найти много информации о том, как обрабатывать то, что может показаться распространенным Проблема:

MyObject one = new MyObject();
one.setFoo("foo");
one.setBar(null);

MyObject two = new MyObject();
two.setFoo("foo");
two.setBar((short) 0);

int oneHash = HashCodeBuilder.reflectionHashCode(one);
int twoHash = HashCodeBuilder.reflectionHashCode(two);

System.out.println("oneHash: " + oneHash);
System.out.println("twoHash: " + twoHash);
System.out.println("Bar equality: " + Objects.equals(one.getBar(), two.getBar()));

Предыдущий код создает следующий вывод, который показывает, что оба объекта имеют одинаковый хэш-код, несмотря на то, что они не равны:

oneHash: 3781511
twoHash: 3781511
Bar equality: false

Определение MyObject:

public class MyObject {
    private String foo;
    private Short bar;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public Short getBar() {
        return bar;
    }

    public void setBar(Short bar) {
        this.bar = bar;
    }
}

Хотя я мог бы, возможно, понять нулевые Numeri c и 0 Numeri c, имеющие одинаковое значение ha sh, в чисто математическом смысле, в любом практическом случае это приводит к тому, что неравные объекты имеют одинаковые хэш-код, который может привести к довольно серьезным проблемам коллизий.

Разъяснение / усложнение: хотя я бы хотел просто вызывать equals() или hashcode() для объекта, кодовая база, с которой я работаю, к сожалению, сравнивая два Object s, что означает, что я не имею никакого представления о том, действительно ли equals() или hashcode() определено для любого заданного входа, d Я не могу редактировать определения классов для добавления этих методов в тех случаях, когда они отсутствуют. Вероятно, поэтому первоначальный автор этого кода решил использовать reflectionHashCode(). Имея это в виду, существует ли программное c / основанное на коде решение или обходной путь для этой проблемы, такой как альтернативная библиотека, для которой не требуется определять equals() или hashcode() для сравниваемых объектов?

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Всегда существует вероятность возникновения кодов ha sh даже для объектов с совершенно разными значениями. В конце концов вы отображаете бесконечное число всех возможных значений объекта в 32-битное целое число. Это все еще работает, потому что структуры данных, которые используют преимущества, имеют коды, такие как наборы и карты, дополнительно используют .equals для проверки на равенство объектов.

0 голосов
/ 18 апреля 2020

Основанное на коде решение состоит в том, чтобы реализовать функцию ha sh таким образом, чтобы различать ноль и 0. Существует множество способов сделать это, вот один из них:

// this could be called hashCode, but you don't want to override hashCode
public int yourCustomHashFunction() {
    if (bar == null) {
        return Objects.hashCode(foo, 1234567);
    } else {
        return Objects.hashCode(foo, bar);
    }
}

Так как bar - это Short, значение вне допустимого диапазона для short, например, 1234567, вряд ли приведет к коллизиям с действительными короткими значениями.

...