@iskateli

Сравнение чего с чем идёт в методе equals?

Контекст из книги Брюс Эккель "Философия Java" (полное издание) стр.674 - 677.

Сначала автор создаёт наивную реализацию сравнения и показывает что она не работает.

Например, рассмотрим систему прогноза погоды, которая ставит в соответствие объекты Groundhog (сурок) объектам Prediction (прогноз погоды). Все выглядит довольно просто — вы создаете два класса: Groundhog для ключей таблицы и Prediction для сопоставленного
ему значения:

//: containers/Groundhog.java
public class Groundhog {
   protected int number;
   public Groundhog(int n) { number = n; }
   public String toString() {
      return "Groundhog #" + number;
   }
} ///:~

public class Prediction {
   private static Random rand = new Random(47);
   private boolean shadow = rand.nextOouble() > 0.5;
   public String toString() {
     if(shadow)
       return "Six more weeks of Winter!";
     else
       return "Early Spring!";
}
} ///:~

public class SpringDetector {
// Используем Groundhog или класс, производный от него:
public static <T extends Groundhog>
void detectSpring(Class<T> type) throws Exception {
Constructor<T> ghog = type.getConstructor(int.class);
Map<Groundhog,Prediction> map = new HashMap<Groundhog,Prediction>();
for(int i = 0; i < 10j i++)
map.put(ghog.newInstance(i), new Prediction());
print("map = " + map);
Groundhog gh = ghog.newInstance(3);
print("Looking up prediction for " + gh);
if(map.containsKey(gh))
print(map.get(gh));
else
print("Key not found: " + gh);
}
public static void main(String[] args) throws Exception {
detectSpring(Groundhog.class);
}
) /* Output:
map = {Groundhog #3=Early Springl, Groundhog #7=Early
SpringI, Groundhog #5=Early Spring!, Groundhog #9=Six more
weeks of Winter!, Groundhog #8=Six more weeks of Winter!,
Groundhog #0=Six more weeks of Winter!, Groundhog #6=Early
Springl, Groundhog #4=Six more weeks of Winter!, Groundhog
#l=Six more weeks of Winter!, Groundhog #2=Early Spring!}
Looking up prediction for Groundhog #3
Key not found: Groundhog #3


Далее автор говорит что это не работает и надо изменить класс, переопределив hashCode и equals чтобы можно было правильно сравнить.

Все выглядит просто, но тем не менее не работает. Проблема состоит в том, что класс
Groundhog унаследован от общего корневого iomccaObject, а для генерирования хеш-кода
объекта используется реализация hashCode() этого класса. По умолчанию этот метод
возвращает адрес объекта. Таким образом, хеш-код первого экземпляра Groundhog(3)
не совпадает с хеш-кодом второго экземпляра Groundhog(3), который применялся
в качестве ключа при поиске.
Можно предположить, что необходимо просто переопределить метод hashCode(), на­
писав в классе свою собственную версию. Но и это не поможет до тех пор, пока вы не
сделаете еще одну вещь: не переопределите метод equals(), который также является
частью класса Object. Этот метод используется картой HashMap для проверки того, равен
ли ваш ключ какому-либо ключу из содержащихся в ней.


Метод equals() в классе Object по умолчанию сводится к сравнению адресов, поэтому
один объект Groundhog(3) никогда не будет равен другому объекту Groundhog(3). Таким
образом, чтобы задействовать ваши собственные классы в качестве ключей HashMap,
необходимо переопределить и метод hashCode(), и метод equals(), как показано в сле­
дующем примере, который исправляет ошибку предыдущей программы:


//: containers/Groundhog2.java
// Класс, используемый в качестве ключа HashMap,
// должен переопределять hashCode() и equals().
public class Groundhog2 extends Groundhog {
   public Groundhog2(int n) { super(n); }
   public int hashCode() { return number; }
   public boolean equals(Object о) {
      return о instanceof Groundhog2 &&
     (number == ((Groundhog2)o).number);
   }
} ///:~
//: containers/SpringDetector2.java
// Работоспособный класс ключа
public class SpringDetector2 {
public static void main(String[] args) throws Exception {
SpringDetector.detectSpring(Groundhog2.class);
}
> /* Output:
map = {Groundhog #2=Early Spring!, Groundhog #4=Six more
weeks of Winter!, Groundhog #9=Six more weeks of Winter!,
Groundhog #8=Six more weeks of Winter!, Groundhog #6=Early
Spring!, Groundhog tl=Six more weeks of Winter!, Groundhog
#3=Early Spring!, Groundhog #7=Early Spring!, Groundhog
#5=Early Spring!, Groundhog #0=Six more weeks of Winter!}
Looking up prediction for Groundhog #3
Early Spring!
*///:~


далее непонятно что с чем сравнивается в этой строке
(number == ((Groundhog2)o).number);

number это же объявленный protected int number; в классе public class Groundhog, тогда что значит ((Groundhog2)o).number ?
И как это кстати читается? Поле объекта-аргумента Object о приведённое к классу Groundhog2 ?

Далее автор пишет, что
Здесь метод equals() основывается на номере сурка; таким образом, если два объекта Groundhog2 существуют как ключи в HashMap под одним и тем же номером, объекты будут считаться неравными.

Я уже совсем запутался, если номера(ключи) у них одинаковые то и они должны быть равны, разве нет?
  • Вопрос задан
  • 143 просмотра
Пригласить эксперта
Ответы на вопрос 1
azerphoenix
@azerphoenix Куратор тега Java
Java Software Engineer
Добрый день.
Сравнивать объекты можно при помощи ==, либо equals()
НО!
При сравнении двух объектов при помощи == будут сравниваться ССЫЛКИ на объекты.
При сравнении двух объектов методом equals() он сравнит объекты, так как в классе Object метод equals():
public boolean equals(Object obj) {
        return (this == obj);
    }


При создании пользовательского класса, принято переопределять метод equals() таким образом, что бы учитывались переменные объекта.


(number == ((Groundhog2)o).number);
В данном случе он объект о приводит к типу Groundhog2, получает из него поле number и сравнивает с левой частью.

Также полезным будет прочитать про String & String Pool. И разницу между == & equals()
Например,
public static void main(String ... args) {
    String a = "Hello";
    String b = "Hello";
    boolean result1 = a == b;
    boolean result2 = a.equals(b);
    System.out.println(result1);
    System.out.println(result2);
    String c = new String("Hello");
    String d = new String("Hello");
    boolean result3 = c == d;
    boolean result4 = c.equals(d);
    System.out.println(result3);
    System.out.println(result4);
  }
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы