简短回答: Java 可以自动将int
s 和long
s 扩大到float
s 和double
s,但 Java 会选择扩大到 a float
,因为它比 a 更小(就内存占用而言)double
。您可以double
通过将参数显式转换为 a 来调用该方法的版本double
:
System.out.print(m((double)a1) + "," + m((double)b1));
长答案: Java 中的每种原始数据类型都有一个大小(以字节为单位),它决定了给定原始数据可以容纳多少信息(或者更确切地说,是什么范围的值)。下表显示了一些 Java 原始数据类型的大小:
byte 1 byte
short 2 bytes
char 2 bytes
int 4 bytes
float 4 bytes
long 8 bytes
double 8 bytes
在某些情况下,Java 会自动为您“扩展”值,遵循Java 语言规范中一些明确定义的规则。以下扩展原语转换由 Java 自动执行:
byte
到short
, int
, long
, float
, 或double
short
到int
, long
, float
, 或double
char
到int
, long
, float
, 或double
int
到long
, float
, 或double
long
到float
或double
float
到double
适用于这种情况的其他规则是:
- 加宽不会丢失有关数值整体大小的信息。
- 从一个整数类型扩大到另一个整数类型根本不会丢失任何信息;数值被完全保留。
int
将 a或值扩大long
到 afloat
或将long
值扩大到 adouble
可能会导致精度损失。
例如,Java 可以安全地将 anint
扩展为 along
而根本不改变数值,因为两者都是整数类型并且 along
大于 an int
(参见规则 2)。Java 也可以将 a 扩大int
到 a float
,但可能会损失精度。下面的示例代码演示了这种精度损失。
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);
}
第一次调用foo(float)
按预期打印“123.0”。值“ int
123”被扩大到float
值“123.0”。第二个调用打印“1.23456794E9”,当您考虑规则 3 时,这是有道理的。值“1234567940”与“1234567890”的量级相同,但精度较低。
另一条关键信息:当存在多个重载方法时,Java 通过选择具有最小参数类型(就内存占用而言)的方法来确定调用哪个方法,以便给定参数能够扩展为参数类型。换句话说,你传递给方法的数量必须能够扩大到方法的参数类型,如果多个重载方法满足该要求,Java 将选择参数类型最小的方法。
在您的情况下,您将 anint
和 a传递long
给两个重载方法之一。Java 将查看方法m(float)
并m(double)
确定调用哪个方法。anint
可以扩大到 afloat
和a double
,但是 a float
(4 个字节)小于 a double
(8 个字节),所以 Java 会选择调用m(float)
. 当您使用long
参数调用方法时也是如此:float
选择它是因为它是 along
可以扩展到的最小数据类型。