1

I want to compare the stats for two people using a custom made equals method that will override the equals method in the Object class. Since the return type of this equals method will be a boolean, I know that I need to pass in the (Object obj) parameter. As I define the new equals method, I was taught that I need to first do a check that the obj class does not match the instance class. Once that is verified, I type-cast the obj class to the instance class, and can carry on with the rest of the code.

However, I do not understand why I need to verify that the obj class does not match the instance class. I thought the two classes are supposed to not match, hence the need for the type-cast.

Can anybody tell me why we need to verify that the obj class does not match the instance class? The code I am working on is written below.

public boolean equals(Object obj) {
    if (obj == null || obj.getClass() != this.getClass())
        return false;
    else {
        Person pp2 = (Person) obj;

        if (this.name.equals(pp2.name) && this.age == pp2.age)
            return true;
        else
            return false;
    }
}

public static void main(String[] args) {
     Person ps1 = new Person("Buddy", 14);
     Person ps2 = new Person("Buddy", 14);

     if (ps1.equals(ps2))
        System.out.println("Same");
}
Omar N
  • 1,720
  • 2
  • 21
  • 33
  • There may be two different class which have same variables. Student vs Person, both have name and age, but they are different classes. – Sedat Polat Oct 08 '15 at 06:09
  • on a sidenode, using `obj instanceof Person` will do both, check for class equality and if the obj is not null – SomeJavaGuy Oct 08 '15 at 06:11
  • Since the ps2 is from the Person class, and obj is from the Object class, wouldn't the class match verification always fail as soon as you call ps1.equals.ps2 before you can type-cast anything? That is why I am confused. – Omar N Oct 08 '15 at 06:15
  • @OmarN ps2.equals(new Person()) will make obj instance of person. so getClass wil return Person class. – Sedat Polat Oct 08 '15 at 06:17
  • Gotcha, understood. Thank you! – Omar N Oct 08 '15 at 06:26

3 Answers3

4

What you suggest to do is that:

public boolean equals(Object obj) {
    Person pp2 = (Person) obj;
    return (this.name.equals(pp2.name) && this.age == pp2.age);
}

This would violate the equals() method contract, which clearly says that the method must return false when the two objects are not considered equal. That would not be the case here: the method would throw a ClassCastException instead (or a NullPointerException if obj is null).

Ajinkya
  • 22,324
  • 33
  • 110
  • 161
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • But since we are passing ps2 through equals when we call (ps1.equals(ps2)), and ps2 belongs to the Person class, doesn't this mean that the class types will not match, since obj is of the Object class? Since they do not match classes, that is why I do not understand why we check for it. – Omar N Oct 08 '15 at 06:11
  • a Person is an Object. Referring to a Person as an object doesn't change its type: it's still a Person, and the actual class returned by `obj.getClass()` is still Person. That's polymorphism. And it works lile in real life. Although your phone is an iPhone 6S, I can refer to it as "a phone", "an electronic gadget", or "an object", and that doesn't change the fact that it's still a iPhone 6S. – JB Nizet Oct 08 '15 at 06:16
  • Ok I think I understand. So the verification succeeds because the Object class equals the Person class since Person is a subclass of Object? – Omar N Oct 08 '15 at 06:18
  • Almost. You can refer to the Person instance as an Object because the class Person extends the class Object. That's why you can call `equals()` with a Person as argument. `obj.getClass()` returns the class Person because obj is, really, an instance of the class Person. It would return the class Dog if obj was a reference to an instance of Dog. But Dog can also be referred to as an Object, because it also extends Object. – JB Nizet Oct 08 '15 at 06:21
  • .equals(null); will throw NullPointerException instead of ClassCastException. – Sedat Polat Oct 08 '15 at 06:21
  • 2
    @sedpol have you considered reading the answer. It says that. Explicitely. – JB Nizet Oct 08 '15 at 06:22
  • @JBNizet sorry for that, I read "instead (or " as "instead of". Then, I think the new question is http://stackoverflow.com/questions/2887761/is-it-a-bad-idea-if-equalsnull-throws-nullpointerexception-instead – Sedat Polat Oct 08 '15 at 06:49
2

If you do not check for the type of the other obj, then you might get a ClassCastException when someone calls

new Person("Jim",12).equals(new ArrayList())

You don't want that. You want to return false instead of crashing.

Thilo
  • 257,207
  • 101
  • 511
  • 656
-1

You can use:

if (obj instanceof Person){
}
  • Using instanceof instead of checking for class identity would violate the contract for equals because it breaks symmetry. – Drunix Oct 08 '15 at 06:13
  • @Drunix: Potentially, yes. But you could match all other subclasses' `equals` implementations to preserve symmetry. In fact, this is actually done by things like `List`. They are supposed to be equal, even if the container class is different. – Thilo Oct 08 '15 at 06:26