HashMap добавляет объект с равным true и тем же хэш-кодом

Я пытаюсь создать пользовательские объекты для HashMap и написал код для методов hashcode и equals. При добавлении объектов в HashMap метод equals имеет значение true, а hashcode возвращает одно и то же значение для обоих объектов, а HashMap добавляет оба объекта как разные объекты. Как это может быть возможным? Ниже мой код:

class B {
    String name;
    int id;

    public B(String name, int id)
    {
        this.name=name;
        this.id=id;
    }

    public boolean equals(B b){
        if(this==b)
            return true;
        if(b==null)
            return false;
        if(this.name.equals(b.name) && this.id==b.id)
            return true;
        else
            return false;
    }

    public int hashcode(){
        return this.id;
    }

    public String toString(){
        return "name: "+name+" id: "+id;
    }
}

Для тестирования вышеприведенного кода я добавил в свой основной класс следующее:

HashMap<B,String> sample=new HashMap<>();
B b1 = new B("Volga",1);
B b2 = new B("Volga",1);
System.out.println(b1.equals(b2));
System.out.println(b1.hashcode()+"    "+b2.hashcode());
sample.put(b1, "wrog");
sample.put(b2,"wrog");
System.out.println(sample);

Это производит следующий вывод:

true
1    1
{name: Volga id: 1=wrog, name: Volga id: 1=wrog}

Может кто-нибудь объяснить, почему это происходит?


person volga dr    schedule 17.08.2018    source источник
comment
Ваш метод equals не переопределяет метод из Object. Он должен принимать Object в качестве аргумента, а не B.   -  person maba    schedule 17.08.2018
comment
всегда добавляйте аннотацию @Overrideк методу, который должен переопределять или реализовывать метод. Мало того, что это документирует это, но если вы сделаете только что сделанную ошибку, компилятор откажется компилировать.   -  person JB Nizet    schedule 17.08.2018
comment
Также есть опечатка в hashcode. Должно быть hashCode с большой буквы C...   -  person Shanu Gupta    schedule 17.08.2018
comment
Спасибо, я пропустил это, и это было проблемой. теперь работает нормально!!!   -  person volga dr    schedule 17.08.2018


Ответы (3)


У вас есть две проблемы здесь:

  1. Вместо реализации equals(B) вам следовало реализовать equals(Object) (Javadoc)
  2. Он должен быть hashCode() вместо hashcode() (Javadoc)

Рабочая реализация может выглядеть так:

class B {
    String name;
    int id;

    public B(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public int hashCode() {
        return this.id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        B other = (B) obj;
        if (id != other.id) {
            return false;
        }
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "name: " + name + " id: " + id;
    }
}

В качестве общего совета обязательно укажите аннотацию @Override. Ваша среда IDE и компилятор Java (javac) могут помочь вам выявить такие проблемы.

person thokuest    schedule 17.08.2018
comment
если вы работаете в среде IDE, такой как Eclipse, IntelliJ IDEA, Netbeans и т.п., обязательно укажите аннотацию @Override. Проверка не связана с функциями IDE. @Override вызовет ошибку компиляции. Так что просто javac достаточно, чтобы обнаружить это. - person davidxxx; 17.08.2018

На самом деле вы не переопределяете ни метод hashCode, ни метод equals для java.lang.Object из-за опечатки (вы использовали hashcode) и использования неправильного параметра в методе equals.

Фактическая реализация, которая работает для обоих, будет:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    B b = (B) o;
    return id == b.id &&
            Objects.equals(name, b.name);
}

@Override
public int hashCode() {
    return Objects.hash(name, id);
}

Эта реализация была фактически сгенерирована IntelliJ IDEA. Что мне действительно нравится в этой реализации, так это то, что она использует метод java.util.Objects.hash(), который значительно упрощает генерацию hashCode и был представлен в Java 7.

person gil.fernandes    schedule 17.08.2018

Вы должны переопределить методы equals(Object) и hashCode() вместо equals(B b) и hashcode().

Попробуйте реализовать методы со следующей подписью, и это должно работать:

@Override
public boolean equals(Object o){...}

@Override
public int hashCode() {...}

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

person Pankaj Singhal    schedule 17.08.2018