Type conversion and method overloading - java

This is the sample code :
public class OverloadingExample {
public void display(Object obj){
System.out.println("Inside object");
}
public void display(Double doub){
System.out.println("Inside double");
}
public static void main(String args[]){
new OverloadingExample().display(null);
}
}
Output:
Inside double
Can anyone please explain me why the overloaded method with Double parameter is called instead of that with Object ?

Yes - because Double is more specific than Object. There's a conversion from Double to Object, but not the other way round, which is what makes it more specific.
See section 15.12.2.5 of the JLS for more information. The details are pretty hard to follow, but this helps:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
So here, any invocation of display(Double doub) could be handled by display(Object obj) but not the other way round.

Related

Java Method Overloading and Wrapper Classes [duplicate]

This question already has answers here:
How is an overloaded method chosen when a parameter is the literal null value?
(8 answers)
Closed 4 years ago.
Can some one please explain in more detail.
public class Car
{
public void disp(Object o)
{
System.out.println("Object called :");
}
public void disp(String s)
{
System.out.println("String called :"+s);
}
}
Calling the main method as below
public class CarMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car car=new Car();
car.disp(null);
}
}
Output : String Called : null
2nd scenario if I will pass Integer instead of Object in disp(Object o) then i am getting error as "The method disp(Integer) is ambiguous for the type Car"
As per understanding Java wrapper plays the major role here, but need well explanations.
Please help.
Let us take both the cases one by one:
Case 1: When we have two disp overloaded function, one with parameter Object and other with parameter String:
public void disp(String s) { System.out.println("String called :"+s); }
public void disp(Object o) { System.out.println("Object called :"); }
In this case, it will refer to the most specific method. According to Java Docs JLS 15.12.2.5:
A method m1 is strictly more specific than another method m2 if and
only if m1 is more specific than m2 and m2 is not more specific than
m1.
So, in above case, the function accepting String is more specific then the one accepting Object, however, the opposite is not true.
Hence, in this case, when null is passed, it will go to the method with parameter String. But if you will pass (Object)null, it will go to the method with parameter Object.
car.disp(null); --> String called :null
car.disp((Object)null); --> Object called :
Case 2: When we have two disp overloaded function, one with parameter String and one with parameter Integer.
public void disp(String s) { System.out.println("String called :"+s); }
public void disp(Integer i) { System.out.println("Integer called :"+ i); }
In this case, as none of the method is more specific then the other and both the function can accept null value, an appropriate function can not be decided in case of null. However, if you will pass (Integer)null or (String)null, no ambiguity will be there and appropriate function can be called.
car.disp(null); --> Compile time error (The method disp(String) is ambiguous for the type Car)
car.disp((Integer)null); --> Integer called :null
car.disp((String)null); --> String called :null
As the commenters have pointed out, you don't have a disp(Integer..) method, and if you do provide that, the method call works fine with disp(12).
As for the question of disp(null), according to the Java language spec:
Overloaded methods and constructors are resolved at compile time by
picking the most specific method or constructor from those which are
applicable.
Basically String is more specific than Object, so even though both apply to null, the String version of the method gets picked.

Primitive vararg parameters in method overloading

Primitives are at it again, breaking rules, I learned before. Well not technically primitive but composed of them.
I learned that whenever there's no method more specific than rest, compile time error occurs as it happens here.
public static void caller(){
z5(); // Error. Neither Integer, nor String is more specific
z5(null); // Error for the same reason
}
public static void z5(Integer...integers){
System.out.println("Integer z5 called");
}
public static void z5(String...strings){
System.out.println("String z5 called");
}
Now comes primitives into the picture.
public static void caller(){
z1(null); // Error cuz [I, [J, [F all are subclass of Object.
z1(); // SURPRISINGLY works and calls the int one. WHY?
}
public static void z1(int...integers){
System.out.println("int z1 called");
}
public static void z1(long...longs){
System.out.println("long z1 called");
}
public static void z1(float...floats){
System.out.println("float z1 called");
}
Expected compile time errors occurs here.
public static void caller(){
z1(null); // Error
z1(); // Error
}
public static void z1(int...integers){
System.out.println("int z1 called");
}
public static void z1(boolean...bools){
System.out.println("bool z1 called");
}
Now my question is, int[], float[], or any array of primitives are not primitive types then Why are they treated differently than other reference types?
--UPDATE--
#john16384 You don't think I read your "Possible duplicate" Varargs in method overloading in Java
Top answer there says You cannot combine var-args, with either widening or boxing. Besides I forgot to mention, OP's code posted there, works fine on my jdk 7.
What exactly is going on which works for (int...is) & (float...fs) but not for (Integer...is) & (Float...fs) and not for (int...is) & (boolean...bool)
Quote from the JLS about varargs invocations when multiple methods are applicable:
15.12.2.5. Choosing the Most Specific Method
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time error. In cases such as an
explicitly typed lambda expression argument (§15.27.1) or a variable
arity invocation (§15.12.2.4), some flexibility is allowed to adapt
one signature to the other.
The important part here is how methods are defined to be more specific. It basically says that int... is more specific than long... because any values you could pass to the first method could also be passed to the second method.
This will also apply to the case where you pass no arguments. int... will be the most specific (it will even see byte... as more specific!).
public static void main(String[] args) {
bla();
}
private static void bla(long... x) {}
private static void bla(int... x) {}
private static void bla(short... x) {}
private static void bla(byte... x) {} // <-- calls this one
The reason you get an error when also creating an overload boolean... is that it now is ambigious which one to call, and the compiler stops before getting to the point where it has to pick the most specific method.

Why Array and Integer constructor are ambigious

I have wrote this program in eclipse and eclipse is complaining that constructor is ambigious. I am not sure why java compiler calling them ambiguous.
public class Ambigious {
public Ambigious(float[] a){
System.out.println("array constructor");
}
public Ambigious(Integer a){
System.out.println("Integer constructor");
}
public static void main(String[] args) {
new Ambigious(null);
}
}
but this is not
public class Ambigious {
public Ambigious(Object a){
System.out.println("object constructor");
}
public Ambigious(float[] a){
System.out.println("array constructor");
}
public static void main(String[] args) {
new Ambigious(null);
}
}
Problem 1:
Both float[] and Integer are Objects so null can be applied to both constructors.
Since there isn't any best suited type compiler can't decide which one should be used.
Problem 2:
In case of Object and Integer types the most suited one is chosen. For instance if you would pass new Integer(1) as argument then both constructors could be applied because Integer is also Object, but compiler binds this invocation with code from constructor with most precise argument types.
Similarly with null, since it can be used as Object and Integer compiler assumes that the more precise type would be Integer.
To solve this kind of problems you can specify which type null should represent by casting
new Ambigious((Integer)null);
You can also try changing one of argument types to non-Object like
public Ambigious(int a){//primitive type
instead of
public Ambigious(Integer a){
As the exception raised states, reference to Ambigious is ambiguous, both constructor Ambigious(float[]) in Ambigious and constructor Ambigious(Integer) in Ambigious match.
This means that both constructors can take the value you passed, which is null.

Passing parameter as Wrapper class and overriding

Please clarify my doubt on overriding, When I am calling a method which is not overrided, the method that is being called is form parent class, please give brief explanation on this, The example is like this
public class A {
public void test(int x){
System.out.println("Haiiiiiii");
}
}
public class B extends A{
public void test(Integer x){
System.out.println("hiii Im b's method");
}
}
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
B a=new B();
a.test(2);
}
}
I'm calling b's method but in B class the method takes wrapper class as parameter.
There are 2 methods. One accept int and other accept Integer type. So when you call test() method first it try to find a suitable method without doing any autoboxing. In that case it can find the parent class test() method which accept an int. Therefore java will execute that.
If in case it wouldn't exist then it will try to autobox your parameter and check if there a suitable method. In that case your child class method will get execute.
Edited
Java will always pick the most specific method for a type. Casting/autoboxing/unboxing only when it has to.
If you wanna call child class method you can try
a.test(new Integer(2));
In this case overriding not happen. since overloading when you call it will call the method accept input argument as int.
The compile lets you auto-box and unbox between primitives and wrappers but this doesn't make one a sub-class of the other. int and Integer are two different types hence both of them when used in the method act as two different method (as in your case)
Refer below link for a much clearer explanation
int does not override Integer in Java

What is the type on null as a method argument?

So here it is this example
public static void main(String[] args) {
new Stuff(null);
new Stuff("a");
new Stuff(1);
}
and class Stuff is defined as follow
public class Stuff {
Stuff(Object o){
System.out.println("object");
}
Stuff(String s){
System.out.println("string");
}
}
The output is
string
string
object
How does Java tell the null is a String? If I change Stuff to
public class Stuff {
Stuff(String s){
System.out.println("string");
}
Stuff(Integer o){
System.out.println("Integer");
}
}
I get compilation error for Stuff(null):
The constructore Stuff(String) is ambigous.
Again, why does Java "decide" null is a String?
The compiler first lists all applicable methods. In your case, both are applicable.
It then tries to find a method which is more specific than the other(s).
In your first example, String is a subclass of Object and is therefore more specific.
In your second example, both methods are applicable (String and Integer) but neither is more specific than the other (String is not a subclass of Integer which is not a subclass of String). So there is an ambiguity, hence the compiler error.
The full algorithm to determine which method should be chosen is defined in the JLS.
Because String is more specific then Object. Java always tries to use more specific match when figuring out which constructor or method to use.

Categories

Resources