-1

I have a Student class that extends a Person class. I do not have an equals method inside of my super class, just the two in my subclass as shown in the image. I am trying to understand the runtime behavior of my 2nd, 3rd and 4th print statements. Statement 1 calls the equals method that takes a student parameter, which makes sense as both objects being compared are declared type Student. However, statement 2 calls the equals method which takes a person parameter while the last 2 statements call the equals method in the Object class. Can somebody explain why is this so when Java is dynamically typed and the actual runtime object is always a Student. Apologies for any errors in advance! I'm new here and new to Java. I'm not too concerned with the output of each method just which one is being called and why.

public boolean equals(Student s) {
    System.out.println("inside student equals");
    return true;
}

public boolean equals(Person p) {
    System.out.println("inside person equals");
    return false;
}

public static void main(String[] args) {
    Student s1 = new Student("John", "1", 10, 1.0, 10);
    Student s2 = new Student("John", "1", 10, 1.0, 10);

    Person s3 = new Student("John", "1", 10, 1.0, 10);
    Person s4 = new Student("John", "1", 10, 1.0, 10);

    System.out.println(s1.equals(s2)); // 1
    System.out.println(s1.equals(s3)); // 2

    System.out.println(s3.equals(s4)); // 3
    System.out.println(s3.equals(s1)); // 4
}

Output:

    inside student equals
    true
    inside person equals
    false
    false
    false
amuu00
  • 71
  • 5

3 Answers3

1

The biggest mistake you have done is, missing @Override annotation with the equals method. Once you will do it e.g.

@Override
public boolean equals(Object obj) {
    System.out.println("inside person equals");
    return false;
}

and

@Override
public boolean equals(Object obj) {
    System.out.println("inside student equals");
    return true;
}

Once you do it, your IDE will fail the compilation forcing you to correct the definitions which should be Object instead of Person or Student types as the parameters.

About the output you are getting:

In none of the four calls, the overridden Object#equals will be called.

There is no doubt that Student#equals will be called in the first call as both the references are of Student type. In the remaining three calls, Person#equals will be called because of the closest match.

You can check this demo for an illustration.

Update

If you put both the equals methods inside Student as shown here, it should be even easier for you to understand the output.

s1.equals(s2) // 1 -> "inside student equals" will be printed because the param, s2 is of type, Student
s1.equals(s3) // 2 -> "inside person equals" will be printed because the param, s3 is of type, Person

s3.equals(s4) // 3 -> s3 is of type, Person but Person has not overridden equals, therefore Object#equals will be called
s3.equals(s1) // 4 -> s3 is of type, Person but Person has not overridden equals, therefore Object#equals will be called

If you want Student#equals to be called in the last two cases as well, you will need to cast s3 to Student as shown below:

System.out.println(((Student) s3).equals(s4)); // 3.1
System.out.println(((Student) s3).equals(s1)); // 4.1
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • Hi Arvind, thanks for your response. What I'm having trouble understanding is that if Object equals is never being called and just the Person equals like you said, then why isn't it printing "inside person equals" in the last two statements? – amuu00 Dec 20 '20 at 19:13
  • @amuu00 - I've added a link to the demo. Feel free to comment in case of any doubt/issue. – Arvind Kumar Avinash Dec 20 '20 at 19:23
  • That makes perfect sense however it wasn't really my question. I have both equals(Student s) and equals(Person p) inside the subclass and none in my superclass. Can you help explain print statements 3 and 4? I get the first two – amuu00 Dec 20 '20 at 19:34
  • @amuu00 - I've added an update section to explain the output for this requirement. Feel free to comment in case of any doubt/issue. – Arvind Kumar Avinash Dec 20 '20 at 19:45
  • Done! Thanks Arvind, my confusion was coming from the following: s3.equals(s4) //s3 is of type Person at declaration time and the code compiles because it inherits equals method from object class and the compiler is happy. However, at runtime since Java is dynamically typed and we have Person s3 = new Student(), it'll run the equals inside of Student class. You see? And I was thinking it should run one of the two equals methods in the Student class. – amuu00 Dec 20 '20 at 20:03
  • I'm still a little confused why that isn't the case tbh – amuu00 Dec 20 '20 at 20:04
  • @amuu00 - I have added two more statements (as `3.1` and `4.1`) in the **Update** section. I also encourage you to check this [discussion](https://stackoverflow.com/questions/51416125/child-class-method-cannot-be-accessed-when-a-child-class-object-has-a-reference). Feel free to comment in case of any doubt/issue. – Arvind Kumar Avinash Dec 20 '20 at 20:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226210/discussion-between-amuu00-and-arvind-kumar-avinash). – amuu00 Dec 20 '20 at 20:24
0

Where Person object is the parameter the overloaded equals of Student is called. That is why you get the print statement. If you want it to be compared as a Student, then you need to type-cast it.

In cases where equals is called on Person object it ends up returning a false as .equals is not implemented in Person class ... it then defaults to Object's implementation which is "check for Null and then check if the reference is the same ... else return false". You can check the implementation out in JDK's source.

A G
  • 297
  • 1
  • 7
0

Determining which overloaded method is used, is determined at compile time, according to the declared type.

In the 2nd case, you have declared s3 to be a Person, and therefore the equals(Person) method is used.

In the 3rd and 4th cases, you have declared the variable as a Person. Person does not have an equals() method, and therefore the compiler assumes you want to use the default method from Object:

boolean equals(Object o);

You have not overridden that method in any of the classes, and so that default method is what is used at run time.

fishinear
  • 6,101
  • 3
  • 36
  • 84