Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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.

share|improve this question
    
Note that adding @Override to the second m1 will stop this from happening IRL :) –  Navin 2 days ago
    
possible duplicate of Java overloading and inheritance rules –  Raedwald yesterday

9 Answers 9

up vote 11 down vote accepted

Your two methods named m1 do not have the same signature; the one in the superclass takes a double, and the one in the subclass takes an int. This means that the compiler will select the method signature to call based on the compile-time type of your variable, which is C1, and will call m1(double). Since at runtime the class C2 doesn't have an overriding version of m1(double), the version from C1 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.

share|improve this answer
    
so, I have to do a mandatory cast? or create C2 c = new C2(); –  Robert Apr 25 at 18:54
    
@Rob3 This question doesn't explain that the method m1 in C2 is overloaded and not overriden. See my answer for a detailed explanation. –  Chetan Kinger Apr 25 at 18:58
    
@Rob3 You'll have to do one or the other to invoke m1(int). Something to change the compile-time type of the target to C2. –  chrylis Apr 25 at 18:58
    
The question title say overloading behavior not override –  Robert Apr 25 at 19:02

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.

share|improve this answer
1  
That's what the OP says. he is overloading the method. –  Alboz Apr 25 at 18:43
    
he is expecting the overloaded method to be called? I don't think hes that dumb –  Distjubo Apr 25 at 18:44
    
I try to call the other method but it not appears.. also I thing that C2 have two method first: m1(double) and second: m1(int) When I called m1(10) and expected that m1(int ) will be invoked. –  Robert Apr 25 at 18:45
    
To call the otherr method, you have to cast the object, example code: ((C2)c).m1(10); –  Distjubo Apr 25 at 18:48
    
@Rob3 read the answer from SRobertz. The method visible to you depend on the variable TYPE and not the actual object. –  Alboz Apr 25 at 18:49

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);

share|improve this answer

Java does method dispatch on static types, and your variable c is of type C1, so m1(int) is not visible, and your 10 is cast to double.

share|improve this answer
    
this seems the shortest and best answer to me. –  Alboz Apr 25 at 18:47
    
This answer is the simplest explanation. In general, it would not be correct to call m1(int) on a C1 object, even if the instance is a C2, because in general objects of type C1 do not have such a method. –  PWhite 2 days ago

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).

share|improve this answer

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).

share|improve this answer

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.

share|improve this answer

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).

share|improve this answer

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();
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.