user133466
user133466

Reputation: 3415

Java parameter confusion

In the code below why is it that o1.equals(o2); calls equals(Object o) not the equals(EqualsTest et) even though o1 and o2 are referencing objects of type EqualsTest!

public class EqualsTest {
      public static <T> boolean equalTest(T o1, T o2) {
          return o1.equals(o2);
      }
      public static void main(String[] args) {
          EqualsTest et1 = new EqualsTest();
          EqualsTest et2 = new EqualsTest();
          System.out.println(et1.equals(et2));
          System.out.println(equalTest(et1, et2));
      }
      public boolean equals(Object o) {
          if (o instanceof EqualsTest) {
              System.out.println("equals(Object)");
              return true;
          }
          return false;
      }
      public boolean equals(EqualsTest et) {
          System.out.println("equals(EqualsTest)");
          return this.equals((Object)et);
      }
}

Upvotes: 3

Views: 202

Answers (3)

Santosh Gokak
Santosh Gokak

Reputation: 3411

Since you have used Overloading the methods are linked at compile time and Java uses the less specific argument type for the polymorphic binding to the callee which is object in this case and not EqualsTest.

Upvotes: 1

Amit Deshpande
Amit Deshpande

Reputation: 19185

As I mentioned in the comment it is because of TypeErasure in java.

Check the byte code which is generated for equalTest. You can clearly see it will invoke method which has Object as parameter.

It is same as calling this.equals((Object)et) which will invoke Object method

// Method descriptor #15 (Ljava/lang/Object;Ljava/lang/Object;)Z
// Signature: <T:Ljava/lang/Object;>(TT;TT;)Z
// Stack: 2, Locals: 2
public static boolean equalTest(java.lang.Object o1, java.lang.Object o2);
0  aload_0 [o1]
1  aload_1 [o2]
2  invokevirtual java.lang.Object.equals(java.lang.Object) : boolean [18]

What you need is

public static <T extends EqualsTest> boolean equalTest(T o1, T o2) {
    return o1.equals(o2);
}

Now Lets check the generated byte code.

public static boolean equalTest(EqualsTest o1, EqualsTest o2);
0  aload_0 [o1]
1  aload_1 [o2]
2  invokevirtual EqualsTest.equals(EqualsTest) : boolean [18]
5  ireturn

As you can see compiler has changed Object to specific type that is EqualsTest because we have used Bounded Type so now if you invoke equalTest it will invoke method with equalTest as parameter

Upvotes: 1

Volker Stolz
Volker Stolz

Reputation: 7402

The compiler finds the corresponding method based on the declared type of the argument, not the most specific one. Since you didn't specify anything for thee T, it defaults to Object, as @nicholas.hauschild correctly points out.

Upvotes: 1

Related Questions