Calling overloaded inherited methods using super c

2020-02-25 07:39发布

I do not understand this Java behavior. I have two classes:

class C1 {
    public void m1(double num) {
        System.out.println("Inside C1.m1(): " + num);
    }
}

class C2 extends C1 {
    public void m1(int num) {
        System.out.println("Inside C2.m1(): " + num);
    }
}

And it is my main:

public class Main {

    public static void main(String[] args) {
        C1 c = new C2();
        c.m1(10);
    }
}

And the result was:

Inside C1.m1(): 10.0

When I expected:

Inside C2.m1(): 10

Also when I try to complete the code syntax, I found this:

Enter image description here

Where is the other m1 of C2 class?

I also check the bytecode of my Main.class and I saw this:

Compiled from "Main.java"
public class com.company.Main {
  public com.company.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/company/C2
       3: dup
       4: invokespecial #3                  // Method com/company/C2."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc2_w        #4                  // double 10.0d
      12: invokevirtual #6                  // Method com/company/C1.m1:(D)V
      15: return
}

The bytecode tell me that it will invoke the C1.m1 (D)V (line 12).

Why the method of C1? I am trying to understand this behavior.

10条回答
▲ chillily
2楼-- · 2020-02-25 08:28

Since C1.m1(double num) is a public method, it inherited C2. So your C2 also has a method, m1(double num), and that's why it is called. From main() you actually called C2.m1(double num).

Note: Now at class C2 you have two overloaded methods - m1(int num) and m1(double num). And C2.m1(int num) is a different method from C2.m1(double num).

查看更多
甜甜的少女心
3楼-- · 2020-02-25 08:30

Method signatures for both methods are different.

public void m1(double num) 
public void m1(int num)

So there is no overriding in this case. Now when you say

    C1 c = new C2();
    c.m1(10);

at compile time, it will se reference is of type C1 which has method public void m1(double num) which is compatible with 10 [int in expanded to double]. So int is promoted to double, and the corresponding method is called (which is also what you see in the bytecodes).

查看更多
Lonely孤独者°
4楼-- · 2020-02-25 08:30

By looking at your code, you are not taking advantage of inheriting to get the answer you want. You have to change this line

C1 c = new C2();

to

C2 c = new C2();
查看更多
Lonely孤独者°
5楼-- · 2020-02-25 08:32

The reason why you see the output as Inside C1.m1(): 10.0 and not Inside C1.m1(): 10 or Inside C2.m1(): 10.0 is because :

  1. You are not overriding the method m1 in C2. You are overloading the m1(doube) method that you inherited from C1 to m1(int) instead.
  2. The C2 class now has two m1 methods. One that is inherited from C1 and has the signature m1(double) and one that is overloaded in C2 and has the signature m1(int)
  3. When the compiler sees the call c.m1(10), it resolves this call based on the reference type. Since the reference type is C1, the compiler is going to resolve this call to m1(double) in C1.
  4. At runtime, the JVM is going to resolve the call to m1(double) in C2 which is the method inherited from C1. (As explained in point 2)

There are two ways in which the m1(int) method can be called :

((C2)c).m1(10);

OR

C2 c = new C2(); c.m1(10);

查看更多
登录 后发表回答