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:
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.
Java chooses the most specific applicable type. In this case m1(int) is not applicable. Emphasis on the reference of class that hold object of same class(c1) or an object of any sub classes of class(c2) & method name and parameter list .
Your method with double parameters is being called because double takes priority over int. This is because an int can be assigned to a double, but not the other way around.
So there are so many things to be consider at the (run) time of method call.
Yes for ur case your main class should be like this
If you call c.m1(10.0) it will call the method of the ancestor as you were expecting at first.
You're doing method overloading in your example (that is adding more methods with the same name and different signature) instead of method overriding (that is changing the implementation of an ancestor's method at a descendent by redeclaring it with the same signature, AKA same name and same type of result and of method arguments - argument names shouldn't matter).
Java does method dispatch on static types, and your variable
c
is of typeC1
, som1(int)
is not visible, and your10
is cast todouble
.Your two methods named
m1
do not have the same signature; the one in the superclass takes adouble
, and the one in the subclass takes anint
. This means that the compiler will select the method signature to call based on the compile-time type of your variable, which isC1
, and will callm1(double)
. Since at runtime the classC2
doesn't have an overriding version ofm1(double)
, the version fromC1
is invoked.The rule is that method signatures are computed at compile time based on compile-time types; method calls are dispatched at runtime based on matching signatures.
It's because of the parameters. The method you call is a method with a double parameter. m1 inside of C2 is not overriding this, instead it's overLOADING it.
If you want to call m1 in C2, you have to cast the reference such that the compiler accepts what you're doing.
You cannot see methods of C2, because you instance variable is declared as C1 and also because they don't have the same signature. You have double parameter in one method and in second a int type which makes them for JVM completely different methods (so no inheritance will work here).
So if you have int type in C1 method then you need to have also int type in C2 method, then JVM will run method from C2 like you wanted.
Also you can cast variable to C2 type then you will be able to access to methods of C2.