Why doesn't my primitive-type-argumented method override the wrapper-type-argumented super class method?
Asked Answered
S

3

9
public class WrapperClasses{
    void overloadedMethod(Number N){
        System.out.println("Number Class Type");
    }

    void overloadedMethod(Double D){
        System.out.println("Double Wrapper Class Type");
    }

    void overloadedMethod(Long L){
        System.out.println("Long Wrapper Class Type");
    }

    public static void main(String[] args){
        int i = 21;
        WrapperClasses wr = new WrapperClasses();

        //wr.overloadedMethod(i);
    }
}

class mine extends WrapperClasses{
    void overloadedMethod(int N){
        System.out.println("Integer Class Type");
    }
    public static void main(String[] args){
        int i = 21;
        WrapperClasses wr = new mine();

        wr.overloadedMethod(i);
    }
}

This prints Number Class Type.

I understand the rules of wrapper class method overloading:

  1. If you are passing a primitive data type as an argument to the method call, the compiler first checks for a method definition which takes the same data type as an argument.
  2. If such a method does not exist, then it checks for a method definition which takes a larger-sized primitive data type than the passed data type. I.e., it tries to perform auto-widening conversion of the passed data type.
  3. If auto-widening conversion is not possible, then it checks for a method definition which takes the corresponding wrapper class type as an argument. I.e., it tries to perform auto-boxing conversion.
  4. If such a method does not exist, then it checks for a method which takes the super class type (Number or Object type) as an argument.
  5. If such a method also does not exist, then the compiler gives a compile-time error.

According to rule 1, it should print Integer Class Type. What am I missing here?

Sheath answered 7/9, 2018 at 7:25 Comment(2)
It checks in 1 the designated class WrapperClasses or wr. The compiler does not make (need not make) the effort to what class wr actually is. In WrapperClasses wr = System.millis() % 2 == 0? new WrapperClasses() : new mine(); that could become unsolvable.Sullen
Compile time wiring.Changsha
L
10

At a language spec level, it is because methods with parameters which differ as being primitive and wrapped primitive types are not considered as override-equivalent. (A fancy way of saying "they just don't because the language spec says so").

But logically, they shouldn't either, at least in the case of an int parameter in a subclass "overriding" a wrapped parameter in a superclass.

By Liskov's Substitution Principle, methods in subclasses must accept at least all the parameters accepted by the method in the superclass.

If the superclass method accepts the wrapped class, it can accept null. If the subclass method were allowed only to accept int, it could not accept null, so it would not be substitutable.

Latimore answered 7/9, 2018 at 7:40 Comment(0)
N
5

Method overload resolution is determined at compile time, based on the compile time type of the variable holding the reference to the instance for which you are calling the method.

void overloadedMethod(int N) is only defined in the sub-class mine. Therefore, when you call a method on a reference whose type is the base class WrapperClasses, only the methods of the base class can be considered for overload resolution.

The int argument that you pass to the method doesn't match any of the 3 methods of the base class, but after it is boxed to Integer, it matches the void overloadedMethod(Number N) method.

If you change your code to

    int i = 21;
    mine wr = new mine();

    wr.overloadedMethod(i);

it will execute void overloadedMethod(int N).

Neckcloth answered 7/9, 2018 at 7:29 Comment(0)
S
3

Polymorphism is performed by the JVM at runtime. For this to work, the two methods must have the same runtime signature.

In the case of covariant return types, the compiler generates bridge methods to allow this to happen, however, the Java language Spec doesn't require such a bridge method for wrappers vs primitives.

There is a number of reasons this might be, however the most likely is backward compatibility. Java 1.0 didn't do this, and even though autoboxing was added more than a decade later, this wasn't allowed to break older code. i.e. wrapper and primitives overloaded each other, not overrode, so they can't now.

Selfdefense answered 7/9, 2018 at 8:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.