Home > Software design >  Equals() method and hashcode() understanding issue
Equals() method and hashcode() understanding issue

Time:04-15

This is a practice exercise from a book by Koffman. Data Structures: Abstraction and Design Using Java, 3rd Edition.

I have a series of questions. I have had 2 attempts at the equals method. Lines 21-29 are what made sense to me logically without checking references, and 32-41 are adapted from the book.

  1. Are lines 20-30 a correct implementation of an equals() override method? Can I have 2 String parameters and check if these parameters match with the Person Objects 2 String parameters?

  2. Lines 33-41 I have no idea what is occurring or if it's correct. I stole the code from the book but changed implementation here for 2 String parameters instead of the 1 Int parameter they had (IDNumber) on page 355 in the textbook.

    2 a) Are these lines correct to start with?

    2 b) What does instanceof on line 34 check for exactly here? Just that Person is an Object too? Or more?

    2 b 1) If there's more to 2a, what else is being checked?

3 ) Line 45 and 46, I've read that this checks the memory address of the object. But given that we only return lastName.hashCode() and firstName.hashCode(), where abouts is it checking for comparison of memory addresses? What is this method actually doing?

1 public class Person {
2   
3   String lastName;
4   String firstName;
5   
6   
7   public Person(String lastName, String firstName) {
8       this.lastName = lastName;
9       this.firstName = firstName;
10  }
11  
12  public String toString() {
13      
14      String result = ("First name: "   firstName  
15              "\nLast name: "   lastName);
16              
17      return result;
18  }
19  
20  public boolean equals(String lastName, String firstName) {
21
22      if (this.lastName == lastName && this.firstName == firstName) {
23  
24          
25          return true;    
26      }
27      
28      return false;
29      
30  }
31  
32  
33  public boolean equals(Object obj) {
34      if (obj instanceof Person) {
35              return firstName.equals(((Person) obj).firstName)
36                      && lastName.equals(((Person) obj).lastName);
37              
38      }
39          
40      return false;
41  }
42  
43  
44  
45   public int hashcode() {
46       return lastName.hashCode()   firstName.hashCode();
47   }
48  
49  
50
51
52 }

CodePudding user response:

Are lines 20-30 a correct implementation of an equals() override method?

No.

this.lastName == lastName

This compares the reference identity of this.lastName with the reference identity of parameter lastName. You don't want that - you can have 2 identical strings that aren't the same actual object. What you want is this.lastName.equals(lastName), though it needs null-guarding. (So, really, if (this.lastName == null) return lastName == null; return this.lastName.equals(lastName);).

public boolean equals(String lastName, String firstName) {

This isn't an equals method. The equals method has signature boolean equals(Object other) {}. Line 33's is the right signature.

return firstName.equals(((Person) obj).firstName)

Isn't nullsafe. equals methods are not supposed to throw anything. See above on how to fix that.

return lastName.hashCode() firstName.hashCode();

Again the null thing is a problem here, otherwise, eh, it's fine. You could do better, but that'd just be an optimization. The reason this is slightly suboptimal is esoteric. (It gives the same hashcode for e.g. "Peter Jackson" and "Jackson Peter", which is slightly suboptimal).

Lines 33-41 I have no idea what is occurring or if it's correct. I stole the code from the book but changed implementation here for 2 String parameters instead of the 1 Int parameter they had (IDNumber) on page 355 in the textbook.

I don't have your textbook, you didn't mention it. Nobody on Stack Overflow can answer this question as a consequence. An equals method must look like public boolean equals(Object other). Period.

What does instanceof on line 34 check for exactly here? Just that Person is an Object too? Or more?

I can ask you if this book is equal to that dog. The answer is a rather obvious: Uh, no.

The same thing is happening here. Object is the supertype of many things. I might be doing this:

Person joe = new Person("joe");
Person jane = new Person("jane");
joe.equals(jane);

In which case we'd have to look at names to figure it out. (the other instanceof Person check would succeed).

But I could also do:

Person joe = new Person("joe");
Dog rover = new Dog("rover");
joe.equals(rover);

In which case the instanceof check will fail, and we want it to, because if you try to cast the parameter to Person, it would fail - it isn't (it's a dog). The equals method should return false, it should not throw an exception.

Line 45 and 46, I've read that this checks the memory address of the object.

You've read a lie then. That's.. just incorrect and makes no sense at all. This invokes the hashCode() method on whatever object the lastName field is pointing at. There's no need to know how it works. It does not return memory addresses. If it did, this would be broken (as the hashCode of 2 objects whose value are identical, but which do not live at the same memory address, must return the same hashcode, that's the point of hashcode: Equal objects must have equal hashcode (but equal hashcode does not neccessarily mean equal objects).

In general you should not be writing your own equals and hashCode implementations. Let java do it (records), your IDE do it (the source menu has a 'generate' optino), or let tools like Project Lombok or AutoValue do it.

CodePudding user response:

Think of a Java object as a person and its hashcode() as the address of the house he/she lives in. Multiple persons can live in the same house (sharing the same hashcode) so once you arrive at the correct house, you will need an additional mechanism to find the actual person you are looking for. That's where equal() comes into play. Two people in that house are seen as "different" if and only if equal() tells you so.

By default, Java's equal() compares the references of the two objects. However, you can override equal() to implement your own criteria of when two people should be treated as the same person. Two people can have completely different identities, but as long as your criteria say that they're equal(), then they are treated as one and the same person.

So, with that in mind

Are lines 20-30 a correct implementation of an equals() override method?

No, since you are comparing two persons, not two string

Lines 33-41 I have no idea what is occurring or if it's correct

33  public boolean equals(Object obj) {
34      if (obj instanceof Person) {
35              return firstName.equals(((Person) obj).firstName)
36                      && lastName.equals(((Person) obj).lastName);
37              
38      }
39          
40          return false;
41  }

Says, you choose a random person in the house and want to check if this person is the same person as another object, but the other object can literally be anything (TV, fridge, trashbin, etc.). As the first step you want to verify that the other object is indeed a person (line 34). If that is the case, then invoke your equal criteria to judge if the two should be treated as the same person (line 35 and 36).

Line 45 and 46, I've read that this checks the memory address of the object. But given that we only return lastName.hashCode() and firstName.hashCode(), where abouts is it checking for comparison of memory addresses? What is this method actually doing?

It returns the address of the "bucket" of memory that the object and possibly other objects also live in. That is, it returns the address of the share house.

  • Related