Reputation: 155
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
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
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:
5
to an Integer
and convert 1.2
to a Double
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
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