Short answer: Java can automatically widen ints and longs to both floats and doubles, but Java will choose to widen to a float because it is smaller (in terms of memory footprint) than a double. You can call the double version of the method by explicitly casting the argument to a double:
System.out.print(m((double)a1) + "," + m((double)b1));
Long answer: Each primitive data type in Java has a size (measured in bytes), which determines how much information (or rather, what range of values) a given primitive can hold. The table below shows the sizes of some of Java's primitive data types:
byte 1 byte
short 2 bytes
char 2 bytes
int 4 bytes
float 4 bytes
long 8 bytes
double 8 bytes
Java will automatically "widen" values for you in certain situations, following some well-defined rules from the Java Language Specification. The following widening primitive conversions are performed by Java automatically:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
The other rules that are applicable to this situation are:
- Widening does not lose information about the overall magnitude of the numeric value.
- Widening from an integral type to another integral type does not lose any information at all; the numeric value is preserved exactly.
- Widening an
int or long value to a float, or of a long value to a double may result in a loss of precision.
For example, Java can safely widen an int to a long without changing the numeric value at all, because both are integral types and a long is larger than an int (see rule 2). Java can also widen an int to a float, but there might be a loss of precision. The sample code below demonstrates this loss of precision.
public static void foo(float f) {
System.out.println(f);
}
public static void main(String[] args) {
int a = 123;
int b = 1234567890;
foo(a);
foo(b);
}
The first call to foo(float) prints "123.0" as expected. The int value "123" is widened to the float value "123.0". The second call prints "1.23456794E9", which makes sense when you take rule 3 into account. The value "1234567940" is the same magnitude as but less precise than "1234567890".
The other piece of information that is key here: when multiple overloaded methods are present, Java determines which method to call by choosing the method with the smallest parameter type (in terms of memory footprint) such that the given argument is capable of being widen to the parameter type. In other words, the number you pass to the method must be capable of being widened to the parameter type of the method, and if multiple overloaded methods satisfy that requirement, Java will choose the method whose parameter type is of the smallest size.
In your case, you are passing an int and a long to one of two overloaded methods. Java will look at methods m(float) and m(double) to determine which method to call. An int can be widened to a float and a double, but a float (4 bytes) is smaller than a double (8 bytes), so Java will choose to call m(float). The same is true when you call the method with a long argument: float is chosen because it's the smallest data type that a long can be widened to.
double:)