Несмотря на то, что значения хеша разные, все же почему мои объекты хранятся в одном месте? - PullRequest
0 голосов
/ 23 декабря 2018

У меня есть Movie класс и Я переопределяю только hashCode() метод .Ниже приведен класс java

public class Movie {

private String actor;
private String name;
private String releaseYr;

public String getActor() {
    return actor;
}

public void setActor(String actor) {
    this.actor = actor;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getReleaseYr() {
    return releaseYr;
}

public void setReleaseYr(String releaseYr) {
    this.releaseYr = releaseYr;
}
@Override
    public int hashCode() {
        return actor.hashCode() + name.hashCode() + releaseYr.hashCode();
    }


}

. Я создал два объекта Movie, и оба значения всех свойств объекта одинаковы и поместили их в HashMap.Ниже приведен код

import java.util.HashMap;

public class Test {

public static void main(String[] args) {

    Movie m1 = new Movie();
    m1.setActor("Akshay");
    m1.setName("Taskvir");
    m1.setReleaseYr("2010");

    Movie m2 = new Movie();
    m2.setActor("Akshay");
    m2.setName("Taskvir");
    m2.setReleaseYr("2010");


    HashMap<Movie, String> map = new HashMap<Movie, String>();

    map.put(m1, "Value of m1");
    map.put(m2, "Value of m2");

}

}

Я получаю ожидаемый результат.Поскольку я переопределяю только метод hashCode (), и оба хеш-значения объекта одинаковы, поэтому они хранятся в одном и том же месте индекса массива таблицы HashMap.Ниже приведен ожидаемый результат в режиме отладки.

enter image description here

Но если я не переопределю метод hashCode (), но переопределю метод equals (), они будутхранится в том же месте индекса массива таблицы HashMap. Хотя я вижу, что значения хеш-функции отличаются .Ниже мой метод equals

@Override
public boolean equals(Object obj) {

    Movie m1 = (Movie) obj;
    boolean result = false;

    if (m1.getActor().equals(this.actor) && m1.getName().equals(this.name)
            && m1.getReleaseYr().equals(this.releaseYr)) {
        result = true;
    }

    return result;
}

Вывод в режиме отладки

enter image description here

Если я не переопределяю методы equals и hashCodeзатем я также получаю тот же неожиданный результат.

Согласно моему пониманию, если я не переопределяю методы equals и hashCode или переопределяю только метод equals, тогда объекты m1 и m2должны храниться в другом месте, так как значения хеш-функции различаются для объектов m1 и m2.Но в этом случае этого не происходит.

Может кто-нибудь объяснить, почему при разных значениях хеша мои объекты хранятся в одном месте?

Я использовал Java 8.

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

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

Оба ваших хеш-кода, полученных с помощью Object.hashCode() (31622540 и 27844196), производят идентичный остаток 4 при делении на 16(начальный размер массива HashMap).

Таким образом, при наличии 4 миллиардов различных хеш-кодов некоторые из них должны оказаться в одном сегменте, так как выделение 4 миллиардов будет пустой тратой памяти.массив элементов для каждой хеш-карты.

Чтобы хеш-карта работала должным образом, важно, чтобы равные объекты давали одинаковый хеш-код.

Если вы переопределяете только метод equals()Object.hashCode() не удовлетворяет этому требованию, и вам также необходимо переопределить hashCode() - в противном случае метод get() не найдет объекты, сохраненные на карте.

Если вы хотитедва фильма должны быть equals(), если их поля равны, вы должны указать соответствующий метод hashCode(), как вы это сделали.

Давайте посмотрим на возможное переопределение cКомбинации.

Ничего не переопределить

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

Только переопределить hashCode ()

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

Переопределите оба hashCode () и equals ()

Оба фильма равны, в конечном итогекак только одна запись хеш-карты, с сохраненным позже значением выигрыша.Это происходит потому, что второй put() находит запись с равным ключом под корзиной хеш-кода и просто заменяет его часть значения.

Только переопределение равно ()

БОЛЬШАЯ ОШИБКА!Оба фильма одинаковы, но это не отражается в вычислениях hashCode(), так что это просто вопрос удачи, если поиск существующего значения смотрит в правильную корзину.

0 голосов
/ 23 декабря 2018

Хэш-коды имеют диапазон огромный , от Integer.MIN_VALUE до Integer.MAX_VALUE, в то время как HashMap обычно имеет гораздо меньшее количество сегментов (по умолчанию 16 для вновь созданного HashMap, по крайней мерес OpenJDK 11).Таким образом, вполне возможно, даже ожидается, что хеш-коды будут конфликтовать, и несколько объектов будут добавлены в один и тот же сегмент.Тем не менее, обратите внимание, что если вы не переопределяете hashCode(), это поведение совершенно случайно, и на него нельзя положиться.

...