Here's a SSCCE which demonstrates the described (IMHO, weird) behavior:
public class Test { public static void print(int param) { System.out.println("int"); } public static void print(float param) { System.out.println("float"); } public static void print(Long param) { //<--Wrapper type System.out.println("Long"); } public static void main(String[] args) { long param = 100L; print(param); // output == float } }
Why does java do that?
To convert from left to right (a widening conversion), there is no cast necessary (which is why long to float is allowed).
Doubles are more precise and the extra storage cost is almost always negligible. So in Java by default 2.1 is a double type. Now to convert double to float you need to cast while assigning double data to double type cast is not required.
Convert long to double Using the doubleValue() Method in Java. If you have a long object, you can simply use the doubleValue() method of the Long class to get a double type value. This method does not take any argument but returns a double after converting a long value.
Long class has the following methods for converting long type value to other primitive types. byte byteValue() returns the value of this Long as a byte. double doubleValue() returns the value of this Long as a double. float floatValue() returns the value of this Long as a float.
Java Language Specification is pretty clear on that (emphasis mine):
15.12.2 Compile-Time Step 2: Determine Method Signature
[...]
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion [...] If no applicable method is found during this phase then processing continues to the second phase. [...]
The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing [...]
The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.
That is, in the first step only print(int)
and print(float)
can be appropriate. The latter matches and no further investigation is made.
The reason for such rules is explained in JLS as well:
This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing.
Imagine that your Test
class was compiled against Java 1.4 (before autoboxing). In that case it's clear: print(float)
must be chosen (assuming we agree why long
to float
is considered safe and can be implicit...) as print(Long)
is completely incompatible with long
argument.
Later you compile the same code against Java 5+. The compiler can:
choose print(Long)
as more "obvious" in this context. Thus after upgrading to Java 5 your program behaves differently...
yield compilation error as the call is ambiguous. Thus, previously correct code is no longer compiling under Java 5 (which AFAIR is never the case)
...or preserve old semantics and call the same method as under Java 1.4
You should now understand why print(float)
is used - because it would have been chosen under Java 1.4. And Java has to be backward compatible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With