繁体   English   中英

Java重载 - long和float

[英]Java overloading - long and float

我试图了解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位float foo(float aFloat)

问题为什么Java隐式(没有强制转换)将`long`转换为`float`? 进一步澄清了这个问题的答案。

这是因为JLS#15中的“最具体”规则又引用了JLS#4.10 ,后者又引用了#4.10.1,其中指出:

以下规则定义了基本类型之间的直接超类型关系:

  • double> 1 float

  • 漂浮> 1

  • 长> 1 int

  • int> 1个字符

  • int> 1

  • 短> 1个字节

其中“S> 1 T”表示“T是S的直接子类型”,根据本节紧接的JLS#4.10。

因此,在这种情况下,如果没有long的直接匹配,并且在查看自动装箱之前,编译器会根据上述规则选择最接近的可用超类型,即float

来自JLS的报价:

确定适用性的过程首先确定可能适用的方法(§15.12.2.1)。

该过程的其余部分分为三个阶段,以确保与Java SE 5.0之前的Java编程语言版本兼容。 阶段是:

  1. 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会因为引入变量arity方法,隐式装箱和/或取消装箱而被认为是不明确的。 但是,变量arity方法(第8.4.1节)的声明可以更改为给定方法方法调用表达式选择的方法,因为变量arity方法在第一阶段被视为固定arity方法。 例如,在已声明m(Object)的类中声明m(Object ...)会导致不再为某些调用表达式(例如m(null))选择m(Object),因为m(Object [] )更具体。

  1. 第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第三阶段。 ...

编辑:关于选择 float而不是double:

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符。 Java编程语言使用选择最具体方法的规则。

非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个没有编译时错误的调用,那么一个方法比另一个方法更具体。

重载决策的第一阶段将选择这四种方法中的两种

private static void foo(double aDouble) 
private static void foo(float aFloat) 

因为第一阶段不允许装箱/拆箱( Long ),并且你不能在没有显式铸造的情况下使用int参数传递long方法。 将选择最具体的方法。 在这种情况下, float方法将被解释为最具体而不是double

转换具有优先规则。 它将选择扩大 拳击

因此,在这种情况下,编译器搜索的方法可以接受比长原始数据类型更大(最接近可能更大)的参数作为参数,即float。

如果从发布的示例中删除方法foo(double aDouble)foo(float aFloat) ,则编译器将执行装箱并选择foo(Long aWrapperLong)

在自动装箱以进行重载之前,扩展优先。 原始的包装类(Integer,Long等)从一开始就没有在java中引入,因为java支持向后兼容性,它应该执行在较新版本中以相同方式在一个java版本中编写的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM