I
I
iscateli2022-01-05 19:50:40
Java
iscateli, 2022-01-05 19:50:40

What is compared with what in the equals method?

Context from Bruce Eckel's "Java Philosophy" (complete edition) pp. 674 - 677.

First, the author creates a naive comparison implementation and shows that it doesn't work.

For example, consider a weather forecasting system that maps Groundhog objects to Prediction objects. Everything looks pretty simple - you create two classes: Groundhog for the keys of the table and Prediction for
the value associated with it:

//: 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


Further, the author says that this does not work and the class must be changed by redefining hashCode and equals so that it can be compared correctly.

Everything looks simple, but nevertheless does not work. The problem is that the Groundhog class is inherited from the common root iomccaObject, and the hashCode() implementation of this class is used
to generate the hash code of the object.
By default, this method
returns the address of the object. Thus, the hash code of the first instance of Groundhog(3)
does not match the hash code of the second instance of Groundhog(3), which was used
as a key in the lookup.
We can assume that you just need to override the hashCode() method,
writing your own version in the class. But even that won't help unless you
do one more thing: override the equals() method, which is also
part of the Object class. This method is used by the HashMap to check
if your key is equal to any of the keys it contains.


The equals() method in the Object class is, by default, an address comparison, so
one Groundhog(3) will never be equal to another Groundhog(3). Thus
, to use your own classes as HashMap keys,
you must override both the hashCode() method and the equals() method, as shown in the following
example, which fixes the error in the previous program:


//: 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!
*///:~


further it is not clear what is compared with what in this line
(number == ((Groundhog2)o).number);

number is the declared protected int number; in the public class Groundhog, then what does ((Groundhog2)o).number?
And how does it read by the way? The field of the object-argument Object оcast to the class Groundhog2?

Further, the author writes that
Here, the equals() method is based on the groundhog number; thus, if two Groundhog2 objects exist as keys in the HashMap with the same number, the objects will be considered unequal .

I'm already completely confused, if they have the same numbers (keys), then they should be equal, right?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
O
Orkhan, 2022-01-05
Hasanly @azerphoenix

Good afternoon.
You can compare objects using ==, or equals()
BUT!
When comparing two objects using ==will compare REFERENCES to the objects.
When comparing two objects with a method equals(), it will compare the objects, because in the Object class, the equals() method:

public boolean equals(Object obj) {
        return (this == obj);
    }

When creating a custom class, it is customary to override the equals() method in such a way that object variables are taken into account.

(number == ((Groundhog2)o).number);
In this case, it casts the object оto the Groundhog2 type, gets the number field from it, and compares it to the left side.
It will also be useful to read about String & String Pool. And the difference between ==& equals()
For example,
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);
  }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question