Akash Kaundinya
Akash Kaundinya

Reputation: 109

Vararg methods Override/Overload confusion

Program 1

class B
{
 public void m1(int x)
{
 System.out.println("Super class");
}
}

class A extends B
{
 public void m1(int... x)
{
 System.out.println("Sub class");
}
}

class test1
{
public static void main(String args[])
{
  B b1 = new B();
  b1.m1(10);

  A a = new A();
  a.m1(10);

  B b2 = new A();
  b2.m1(10);
}
}

Output :

  1. Super class
  2. Super class (Unable to understand why superclass ?!)
  3. Super class (Unable to understand why superclass ?!)

Program 2:

class B
{
 public void m1(int... x)
{
 System.out.println("Super class");
}
}

class A extends B
{
 public void m1(int x)
{
 System.out.println("Sub class");
}
}

class test1
{
public static void main(String args[])
{
  B b1 = new B();
  b1.m1(10);

  A a = new A();
  a.m1(10);

  B b2 = new A();
  b2.m1(10);
}
}

Output:

  1. Super class
  2. Sub class (Unable to understand why subclass ?!)
  3. Super class (Unable to understand why superclass ?!)

Hello all, can anyone please explain if there is overriding/overloading resulting in the output ?

Upvotes: 7

Views: 2694

Answers (3)

RCS
RCS

Reputation: 1432

First let me explain about vararg which will help me answer your question better. We use vararg to provide array of primitive as argument of the method.Denoted by elipsis(three dot symbol) and should always be the last parameter of the method. That is why we can't have more than one variable argument into the method. At the time of invoking a method we can either give the value of the argument or you can ignore also. If method is overloaded with variable argument & specific type of parameter then first matching type of parameter will be verified,if matched will be invoked. If matching type of parameter not found then higher type(Widening) will be verified, if found then invoked. At last it will verify the variable argument parameter type. Priority order of verification is -

Same parameter type > Higher type > Variable argument

Now, coming to your question.

In program 1 - A is subclass of B. So class A has both implementation of m1() method with int parameter type and vararg type. Instance of A is calling subclass implementation of m1() method which is same parameter type cause Same parameter type has higher priority than vararg.

A a = new A();
a.m1(10); // will call higher priority m1() with same parameter type
B b2 = new A();
b2.m1(10); // super class has sub class Obj.Based on dynamic disptch concept, it will always call the method declared in super class

In program 2 - A is the sub class of B.Only difference is methods are interchanged here. Class B has m1() method with vararg parameter and class A has int type parameter.

 A a = new A();
 a.m1(10); // Class A has both m1() method with int and vararg.Will call m1() method with int paramter, as it has higher priority over vararg.

 B b2 = new A();
 b2.m1(10); // Storing sub class reference into super class. Dynamic dyspatch says with super class reference we can call only method declared in super class. Super class has m1() method with vararg, will be called.  

Hope this will help.

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1075189

There is no overriding in the question at all, just overloading. Overriding would involve A defining a method with the same signature as a corresponding method in B (for instance, if they both had m1(int)). You're not doing that in either example, as the parameter types differ (int vs. int...).

The mechanics of method signature resolution (choosing which overload to use) are covered by JLS §15.12.2: Compile-Time Step 2: Determine Method Signature. The Java compiler will pick the most specific method it can on the interface defined by the type of the reference (in your case, the type of the variable) if there's any ambiguity.

Note that it's the type of the reference that matters, not the type of the object the reference is referring to. The type of the reference (the variable in your case) is what defines the interface you have to the object. (This is "interface" in the generic OOP sense, rather than the Java-specific thing named after it.) The compiler can only choose from the methods available in that interface.

With that background, the reasons are fairly clear:

Program 1:

  1. Super class - because b1 is of type B, and B only has m1(int), and m1(10) matches it.
  2. Super class - because a is of type A; A has both m1(int) (from B) and also its own m1(int...); the former is more specific, so B's m1(int) is used.
  3. Super class - because b2 is of type B and B only has m1(int).

Program 2:

  1. Super class - because b1 is of type B, and B only has m1(int...), not m1(int).
  2. Sub class - because a is of type A, and A has both m1(int...) (from B) and also its own m1(int); the latter is more specific, and so A's m1(int) is used.
  3. Super class - because b2 is of type B, and B only has m1(int...), not m1(int).

Upvotes: 12

Eran
Eran

Reputation: 393966

There is no overriding in any of your examples, since overriding requires a method with the same name and signature to appear in both the super-class and the sub-class. Most of your examples don't have method overloading either, since only one version of m1 is available for the compiler to choose from.

In the first snippet, references of compile time type B can only see m1(int x). References of compile time type A see both methods, but m1(int x) is still preferred, since it is a better match to your method call (methods with varargs can only be chosen in method overloading resolution if there are no other methods that match the passed parameters and don't contain varargs). Therefore the super-class method is called in all three cases.

In the second snippet, references of compile time type B can only see m1(int... x), which is why that method is called in the 1st and 3rd cases. References of compile time type A see both methods, and this time m1(int x) is preferred again, so the sub-class method is called for the 2nd case.

Upvotes: 5

Related Questions