user1459010
user1459010

Reputation: 155

Java Overloading: Number,Number ; int,Double

In two days i have an exam in java, and i can not figure out the answer to this question:

class ClassA {
 public String foo(Integer x , int y) {
  return "Integer, int";
 }
 public String foo(int x, Double y) {
  return "int, Double";
 }
 public String foo(Number x, Number y) {
  return "Number, Number";
 }
 public String foo(Object x, Object y) {
  return "Object, Object";
 }
 public static void main(String... args) {
  ClassA a = new ClassA();
  System.out.print(a.foo(5, 1.2f) + " ");
  System.out.println(a.foo(null, null));
 }
}

What's the output?

The Answer is:

Number, Number Number, Number

I know that java always chooses the most specified Method, that is why a.foo(null,null); will envoke the Number,Number Method and not the Object,Object Method. But why does a.foo(5,1.2f); also envoke the Number,Number Method and not the int,Double Method??

But one more thing which might be helpful: If i remove the f after 1.2, so that the call is: a.foo(5,1.2); I get a compiler error, that it can not choose between the Number,Number and int,Double Method...

Would be really helpful, if you guys could explain that to me :)

Upvotes: 14

Views: 4500

Answers (3)

Kanagavelu Sugumar
Kanagavelu Sugumar

Reputation: 19260

Generic Answer:

public class OverloadingNumeric {

    public void print(int x){
        System.out.println("int");
    }

    public void print(long x){
        System.out.println("long");
    }

    public void print(float x){
        System.out.println("float");
    }

    public void print(double x){
        System.out.println("double");
    }

    public void print(Integer x){
        System.out.println("Integer");
    }

    public void print(Long x){
        System.out.println("Long");
    }

    public void print(Float x){
        System.out.println("Float");
    }

    public void print(Double x){
        System.out.println("Double");
    }

    public void print(Number x){
        System.out.println("Double");
    }

    public void print(Object x){
        System.out.println("Object");
    }

    public static void main(String[] args) {
        OverloadingNumeric obj = new OverloadingNumeric();
        /*
         * Primitives will take more precedence
         * of calling instead of wrapper class arguments,
         */
        obj.print(10);
        obj.print(10l);
        obj.print(10f);
        obj.print(10d);
        obj.print(10.1);
        //obj.print(999999999999999); Error: this letral type int is out of range
        obj.print(999999999999999l); 

        /*
         * OUTPUT
         * int
         * long
         * float
         * double
         * double
         * long
         */



        /*
         * Assume all primitive argument methods
         *  are commented. then calling the same again
         */
        obj.print(10);
        obj.print(10l);
        obj.print(10f);
        obj.print(10d);
        obj.print(10.1);

        //obj.print((Double)10); //Cannot cast int to Double 
        obj.print((double)10); //Success 
        //obj.print((Float)10); //Cannot cast int to Float 
        obj.print((float)10); //Success 
        //obj.print(null); ERROR AMBIGUOUS

        /*
         * OUTPUT
         * Integer
         * Long
         * Float
         * Double
         * Double
         * Double
         * Float
         * 
         */
    }
}




interface SuperIfc {}

class SuperClass implements SuperIfc{}

class SubClass extends SuperClass {}

public class OverloadingTest {

    public void print(SuperIfc x){
        System.out.println("SuperIfc");
    }

    public void print(SuperClass x){
        System.out.println("SuperClass");
    }

    public void print(SubClass x){
        System.out.println("SubClass");
    }

    public void print(Object x){
        System.out.println("Object");
    }

    public static void main(String[] args) {
        OverloadingTest obj = new OverloadingTest();
        SuperClass superObj = new SuperClass();
        SubClass subObj = new SubClass();
        obj.print(superObj);
        obj.print(subObj);
        obj.print(null);

        obj.print((SuperIfc)superObj);
        obj.print((SuperIfc)subObj);
        obj.print((SuperIfc)null);
        /*
         *  OUTPUT
         * SuperClass
         * SubClass
         * SubClass
         * SuperIfc
         * SuperIfc
         * SuperIfc
         */
    }
}

Upvotes: 1

VoteyDisciple
VoteyDisciple

Reputation: 37803

There are two important factors here.

First, 1.2f is not a Double. It's a Float. The (int, Double) function doesn't match at all. (Number, Number) is the best fit.

Second, even when you change it to 1.2 it is still not a Double. It is a double. That is, it's a primitive, not an object. Now, Java will still happily pass a double into a function that wants a Double without much complaint, but in this case you've confused it by giving it two valid conversions it could make:

  1. Convert 5 to an Integer and convert 1.2 to a Double
  2. Leave 5 as a primitive int but convert 1.2 to a Double.

There isn't a rule for which of those is preferable. Java produces a compiler error that it has an ambiguous function call, and forces you to choose which one you'd prefer (by manually wrapping one or both of them in objects).

As an aside, if you had a method that took (int, double) there would be no ambiguity at all: that method actually matches the existing types of 5 and 1.2, so it would be called. It's the fact that some of the arguments here are wrapper objects that causes the mayhem.

Upvotes: 4

tskuzzy
tskuzzy

Reputation: 36456

1.2f is not wrapped by a Double, it's wrapped by a Float. SinceFloat is not a subclass of Double (they are distinct subclasses of Number), the most specific method signature that can be used is foo(Number,Number).

Once you remove the f, 1.2 will be treated a double (the primitive, not the wrapper class) by default, which can be autoboxed to a Double. However the 5 can also be autoboxed to an Integer, thus causing the ambiguity.

Upvotes: 18

Related Questions