Home > front end >  overloading or overriding equals() method
overloading or overriding equals() method

Time:10-31

I'm a little confused as to what gets called first in the following scenario:

I've got a Person class with a name and an age.

public class Person {
  private int age;
  private String name;

  //constructor, getters, ...
}

I now try to compare two separate Person objects with the same field values i.e. same name, same age

System.out.println(person1.equals(person2));

I obviously receive a false return value because I haven't overloaded the equals(Obj object) method yet.

But say I don't overload it, I instead write another equals() method only with a Person argument:

public equals(Person person) {
  return person.get_age()==this.age && person.get_name().equals(this.name);
}

Which method gets called now and why? The line below still returns false

System.out.println(person1.equals(person2));

unless I force person2 to be interpreted as a Person. The line below therefore returns true

System.out.println(person1.equals((Person)person2));

Here's what's confusing me, I now remove that type cast to Person and for some reason, when I build and run the code again and again, it keeps coming back true. The only way to force it to start returning false again, i.e. to keep taking the default equals(Object obj) method again is by deleting the equals(Person person) method, running the code once, and then pasting back the method I had just deleted. Now the comparison keeps returning false again.

Is some inbetween state being cached by the JVM? I'm a little new to java in all honesty.

CodePudding user response:

Overriding is when you implement a method that has been declared in a superclass. To qualify as an override, the signature of the override must match (within some tolerance) the signature of the method being overridden. ​

Overloading is when you have multiple methods with the same name but different signatures.

In the presence of overloads, which one is called is determined solely by the static types of the arguments at the call site. In your example, you have two overloads of equals:

boolean equals(Object o) { ... }
boolean equals(Person p) { ... }

When you call:

Person p = ...
... equals(p) ...

the overload selection process proceeds as follows:

  • Determine the static types of the arguments.
  • Determine which overloads are applicable (using arity, subtyping, conversion, etc.)
  • If more than one is applicable, determine the most specific one.
  • If two or more are equally specific, a compile-time error is issued.

Here, the argument type is Person, and both overloads are applicable (since a Person is an Object), but equals(Person) is more specific, so that one is called.

If we changed the story slightly:

Object p = new Person(...);
... equals(p) ...

Now, the static type of p is Object, so only the first overload -- equals(Object) -- is applicable. All we know is that it is an Object; that it happens to hold a Person is something that we don't know statically. (We could find it out dynamically with instanceof.)

To summarize:

  • Expressions have both a static (compile-time) and dynamic (run-time) type;
  • Overload selection is done purely on the basis of static types.

Now, you probably don't want to declare equals(Person) for the same problems you're seeing here -- it looks like an override, but really its an overload, and won't get called when you think it does.

CodePudding user response:

Actually Person has two methods:

  • boolean equals(Person);
  • boolean equals(Object); (from Object)

So obviously person2 is not recognized as Person. The likely explanation is forgotten (dropped) generic typing.

Person person = new Person();
List<Person> list = new ArrayList(); // Should have been new ArrayList<>();
...
if (person.equals(list.get(0)) { // equals(Object)

With pre-generic typing the compiler no longer checks and falls back on a List of Objects. Maybe your IDE gives a corresponding warning (orange marker).


Tip:

  • Use getAge and getName; camel case in Java. Conventions in java are kept quite strict everywhere.

  • Do not overload equals and use @Override. So much depends on the original equals, and IDEs are known to warn on personJoop.equals(dog) that it will always fail.

  • Related