我试图理解java重载规则。一切似乎都很好,除了以下,
public static void main(String[] args) {
long aLong = 123L;
foo(aLong);
}
private static void foo(double aDouble) {
System.out.println("Foo aDouble");
}
private static void foo(Long aWrapperLong) {
System.out.println("Foo Wrapper Long");
}
private static void foo(int anInt) {
System.out.println("Foo Int");
}
private static void foo(float aFloat) {
System.out.println("Foo Float");
}
为什么通话会解析为foo(float aFloat)
。我从JLS了解以下内容,
此步骤使用方法的名称和参数的类型 表达式,用于查找既可访问又适用的方法 可能存在多于一种这样的方法,在这种情况下最多 选择具体的一个。
我故意在这里使用Wrapper Long而不是原始的long。长度为64位的原始长度不会以foo(double aDouble)
结尾,而是32位浮点foo(float aFloat)
。
问题Why does Java implicitly (without cast) convert a `long` to a `float`?进一步澄清了这个问题的答案。
答案 0 :(得分:15)
这是因为JLS #15中的“最具体”规则,后者又指JLS #4.10,后者又指#4.10.1,其中指出:
以下规则定义了基元类型之间的直接超类型关系:
double> 1 float
float> 1 long
long> 1 int
int> 1 char
int> 1 short
短> 1 byte
其中“S> 1 T”表示“T是S的直接子类型”,根据本节紧接的JLS#4.10。
所以在这种情况下,如果没有long
上的直接匹配,并且在查看自动装箱之前,编译器会根据上述规则选择最近的可用超类型,即float
答案 1 :(得分:4)
转换具有优先规则。 它将选择加宽而不是拳击。
因此,在这种情况下,编译器搜索的方法可以接受比长原始数据类型更大(最接近可能更大)的参数作为参数,即float。
如果从发布的示例中删除方法 foo(double aDouble)和 foo(float aFloat),则编译器将执行装箱,选择 foo(Long aWrapperLong)
答案 2 :(得分:2)
在自动装箱以进行重载之前,扩展优先。 从一开始就没有在java中引入原语的包装类(Integer,Long& so等),因为java支持向后兼容性,它应该执行在较新版本中以相同方式在一个java版本中编写的代码。