1

I tried to perform a comparison between two objects of the same class. Actually, I wanted to compare the content of the both the objects. Here, the objects are of class Student. In class Student I have overridden the equals() method as shown below. By doing so, will my intention be accomplished (compare the names and birthdays of both students)? If not what is happening here? The problem is that I don't get the answer I expect. The output is false even though it must be true.

public class Main { public static void main(String[] args) { Student a = new Student("John", "Johnny"); Student b = new Student("John", "Johnny"); a.setBirthDate(10, 10, 10); b.setBirthDate(10, 10, 10); boolean ans = Student.equals(a, b); System.out.println(ans); } } 
public class Date { public int day; public int month; public int year; public Date(int d, int m, int y) { this.day = d; this.month = m; this.year = y; } } 
public class Student{ private String firstName; private String lastName; private Date birthDate; public Student(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public void setBirthDate(int day, int month, int year) { Date b_day = new Date(day, month, year); birthDate = b_day; } } @Override public boolean equals(Object student) { System.out.println(this.firstName); System.out.println(this.lastName); System.out.println(this.birthDate); System.out.println(((Student)student).firstName); System.out.println(((Student)student).lastName); System.out.println(((Student)student).birthDate); return super.equals(student); } 

I have overridden the equals method as follows. But still I face the same issue. I suspect that there's something wrong with the Date class. But the problem is that I'm not quite sure of it. Also, I don't understand how to remedy the problem. Can someone please tell me what's wrong here. Thanks in advance.

1
  • 2
    The issue is you overwrote equals, but didn't add any additional checks. Currently, it just prints the values of each object. The line return super.equals(student); is equivalent to not overriding the method in the first place. Commented Feb 1, 2021 at 18:34

2 Answers 2

2

You can structure your equals method similarly to an if statement. You just need to cast the other argument first before your can compare their fields.

@Override public boolean equals(Object o) { // Check if the other object is also a Student if (o instanceof Student) { // Now that we know o is a student, we can safely cast it Student other = (Student) o; // Similarly to how you would write an if statement you can compare each individual field. // Thanks to inheritance, we defer the equality check of each field to its own implementation return this.firstName.equals(other.firstName) && this.lastName.equals(other.lastName) && this.birthDate.equals(other.birthDate); } // Other object was not a student return false; } 

You then need to go write something similar in Date so that when you compare birthDate, it will know what to do.

You can also take this one step farther by using Objects.equals(a, b) instead of a.equals(b). This will ensure you do not get a nullPointerException if a happens to be null when comparing them. However, since this looks to be a school project I imagine you may be expected to either check manually or assume the values will not be null instead of using the standard library.

Sign up to request clarification or add additional context in comments.

3 Comments

Actually, its better to use Objects.equals incase of null possibility. Further hashCode is needed for equals to work. hashCode is uber requirement and equals as the granular requirement. hashCode identifies the bucket and equals checks for equality within the identified bucket.
@HorseAlso while hashCode is important, it is in no way needed for equals to function. Reference: stackoverflow.com/a/4179023/5987669 It sounds like you are describing hashCode's usage in a HashMap. While it is necessary for a hashmap to function correctly, it is not necessary for direct comparisons. Also, I mentioned Objects.equals in the second paragraph, but left it out of the code sample to make it easier to read for a beginner and highlight the usage of inheritance.
Thank you for pointing about Objet.equals in your explanation. Apologies, i missed it. Yes, i was talking about HashMap and it's derivative like ConcurrentHashMap. It is recommended to override hashCode as we can't control the usage of our class by others. So, it is better to seal the class with possibly known good practices to avoid future issues.
0

For equals to work, you need to override hashCode also. Further equality check needs actual comparison of your objects.

Also, any related objects also has to implement hashCode and equals method. In this case Date.

Possible code

import java.util.Objects; class Date { public int day; public int month; public int year; public Date(int d, int m, int y) { this.day = d; this.month = m; this.year = y; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Date date = (Date) o; return day == date.day && month == date.month && year == date.year; } @Override public int hashCode() { return Objects.hash(day, month, year); } } public class Student { private final String firstName; private final String lastName; private Date birthDate; public Student(String firstName, String lastName, Date birthDate) { this.firstName = firstName; this.lastName = lastName; this.birthDate = birthDate; } public static void main(String[] args) { System.out.println(new Student("John", "Johnny", new Date(10, 10, 10)) .equals(new Student("John", "Johnny", new Date(10, 10, 10)))); System.out.println(new Student("John", "Johnny", new Date(11, 10, 10)) .equals(new Student("John", "Johnny", new Date(10, 10, 10)))); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Student student = (Student) o; return Objects.equals(firstName, student.firstName) && Objects.equals(lastName, student.lastName) && Objects.equals(birthDate, student.birthDate); } @Override public int hashCode() { return Objects.hash(firstName, lastName, birthDate); } } 

4 Comments

Implementing hashCode will have no effect on the functionality of equals. It defaults to comparing the object address (Ex: this == other). Implementing hashCode would only work if it compared hashes, but it would still be unreliable due to potential hash collisions.
Just edit your equals method to use getters, as the variables are private.
Since it is a local method it is able to access private members directly. I would recommend avoiding the getters unless there is some functionality you might miss out on.
@AP11, actually this is will be an interesting discussion to have. Generally i prefer using private fields inside hashCode and equals as it resembles the actual state rather than a view. getters provide a view. But if view is the expectation, then even the hashCode should use the view. Otherwise there will be discrepancy in some use cases(say map). As @Locke mentioned, i will also recommend to use attributes directly always (with no exception :) ).