Подтвердить что ты не робот

Java: дублируются объекты, добавляемые в набор?

Если я запустил код ниже, то выход будет равен 2, что означает, что набор содержит 2 элемента. Однако я думаю, что набор должен содержать 1, поскольку оба объекта равны на основе значения hashcode(), а также метода .equals(). Похоже, какая-то очевидная ошибка в моем понимании?

package HELLO;

import java.util.HashSet;
import java.util.Set;

public class Test {

    public static void main(String[] args) throws Exception {
        Set<Alpha> s = new HashSet<Alpha>();
        Alpha a1 = new Alpha();
        Alpha a2 = new Alpha();
        s.add(a1);
        s.add(a2);
        System.out.println(s.size());
    }
}   

class Alpha {
    int a = 10;

    public int hashcode() {
        return a;
    }

    public boolean equals(Object obj) {
        return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
    }

    public String toString() {
        return "Alpha : " + a;
    }
}
4b9b3361

Ответ 1

Ваш метод hash c не переопределяет метод hash C объекта класса Object, и поэтому ваш метод equals нарушает контракт, поскольку он не согласуется с результатами hashCode, и вы можете иметь объекты, которые являются "равными", но имеют разные хэш-коды.

Помните: вы всегда должны использовать аннотацию @Override при переопределении методов, так как это поможет вам поймать эту и подобные ошибки.

@Override  // ** don't forget this annotation
public int hashCode() { // *** note capitalization of the "C"
  return a;
}

Кроме того, вы захотите улучшить форматирование кода, особенно при размещении кода здесь для нашего обзора. Мы сможем лучше понять ваш код и помочь вам, если он будет соответствовать стандартам (почему существуют стандарты). Поэтому старайтесь сохранять свои отступы в соответствии со всеми строками кода, которые находятся в одном и том же блоке с отступом на одном уровне, и вы захотите убедиться, что код базового уровня, включая импорт, объявления внешнего класса и его фигурные фигурные скобки, скрыт влево

import java.util.HashSet;
import java.util.Set;

public class Test {

   public static void main(String[] args) throws Exception {
      Set<Alpha> s = new HashSet<Alpha>();
      Alpha a1 = new Alpha();
      Alpha a2 = new Alpha();
      s.add(a1);
      s.add(a2);
      System.out.println(s.size());
   }
}

class Alpha {
   int a = 10;

   @Override
   public int hashCode() {
      return a;
   }

   public String toString() {
      return "Alpha : " + a;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      Alpha other = (Alpha) obj;
      if (a != other.a)
         return false;
      return true;
   }
}

Для прекрасного обзора по этому вопросу, пожалуйста, прочитайте: Переопределение равных и hashCode в Java

Ответ 2

ваш метод hashcode следует называть hashCode (заглавная буква "C" ).

Если вы планируете переопределять методы, вы должны использовать аннотацию @Override.

Если вы использовали эту аннотацию, вы бы заметили проблему раньше, поскольку код не был скомпилирован.

Ответ 3

Аннотирование @Overrides - переопределить метод с тем же именем в суперклассе ".

@Override
public int hashCode() {
    return a;
}

@Override
public boolean equals(Object obj) {
    return (obj instanceof Alpha && ((Alpha) obj).a == this.a);

}

@Override
public String toString() {
    return "Alpha : " + a;
}