Java 当存在';没有可以接受长时间的方法吗?
下面是一个演示所描述(IMHO,怪异)行为的示例:Java 当存在';没有可以接受长时间的方法吗?,java,type-conversion,overloading,Java,Type Conversion,Overloading,下面是一个演示所描述(IMHO,怪异)行为的示例: 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 para
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
}
}
公共类测试{
公共静态无效打印(int参数){
System.out.println(“int”);
}
公共静态无效打印(浮动参数){
系统输出打印项次(“浮动”);
}
公共静态void print(Long param){/在这一点上非常清楚(我的重点):
15.12.2编译时步骤2:确定方法签名
[……]
第一阶段(§15.12.2.2)在不允许的情况下执行过载分辨率
装箱或取消装箱转换[…]如果在此阶段未找到适用的方法,则继续处理
进入第二阶段。[…]
第二阶段(§15.12.2.3)执行过载解决,同时允许
装箱和拆箱[…]
第三阶段(§15.12.2.4)允许过载与变量相结合
算术方法、装箱和拆箱
也就是说,在第一步中,只有print(int)
和print(float)
是合适的。后者匹配,不做进一步的调查
JLS中也解释了制定此类规则的原因:
这保证了在Java SE 5.0之前的Java编程语言中有效的任何调用都不会因为引入变量arity方法、隐式装箱和/或取消装箱而被认为是不明确的
假设您的Test
类是针对Java 1.4编译的(在自动装箱之前)。在这种情况下,很明显:print(float)
必须被选择(假设我们同意为什么long
到float
被认为是安全的,并且可以是隐式的…)
与long
参数完全不兼容
稍后,您将针对Java 5+编译相同的代码。编译器可以:
- 选择
作为此上下文中更“明显”的选项print(Long)
- 由于调用不明确,因此产生编译错误。因此,以前正确的代码不再在Java 5下编译(AFAIR从未出现过这种情况)
- …或保留旧语义并调用与Java 1.4下相同的方法
print(float)
,因为它是在Java1.4下选择的。Java必须向后兼容。请参阅文档
5.1.2.加宽原语转换
19基元类型上的特定转换称为
原语转换:
- 字节到短、int、long、float或double
- 短到整数、长到浮点或双精度
- 字符到int、long、float或double
- int到long、float或double
- 长到漂浮或翻倍
- 浮动至双倍
因此,从
long
到float
的转换符合规则。Tomasz Nurkiewicz指向规范的相关部分(),但为什么要这样做呢?为了向后兼容,针对1.4和更早版本的源代码应该继续调用相同的重载方法。因此,必须忽略1.5的功能,并且只有在代码无法编译的情况下,才应考虑自动装箱
<为什么>代码>长<代码> >代码>浮点< /代码>可能是隐式的,这只是一个值得怀疑的设计选择。 < P>为什么选择<代码>浮点< /代码>超过<代码>长是后来添加自动装箱的原因,为了向后兼容,它必须进行相同的调用。第一个重载比最后两个重载更匹配(除了第一个重载可以通过适当的向下转换执行)FYI如果从示例中删除
float
重载,它会选择Long
而不是int
:@PaulBellora:感谢这一有趣的观察,它证明了上述规则是有效的。print(int)
单独与long
完全不兼容(请尝试删除print(long)
-编译错误),因此编译器进入第2阶段。+1这似乎表明它之所以如此,是因为它确实如此。你能澄清一下为什么你认为它如此吗?@PeterLawrey:你正确地指出了向后兼容性,我包括了一些更彻底的解释,谢谢!根本上有问题的设计选择是决定隐式转换永远是av即使重载方法或运算符可以采用多种类型,ailable也必须是合法的(没有诊断)。这种设计选择导致Java需要对float f=(float)(1.0/10.0);
,但对double d=1.0f/10.0f;
和if(f==d)进行愚蠢的强制转换…
。第一个表达式中的强制转换既不能提高可读性,也不能引起对潜在错误的注意;相反,如果我正在进行代码检查,并且代码应该具有……后两个表达式所隐含的语义,我希望第二个表达式写为double f=(double)(float)(1.0f/10.0f)第三个是
if((double)f==d),因为在前一种情况下,*预期的*含义可能是将除法作为
double`(而转换为double本身并不能澄清这一点);在后一种情况下,如果没有类型转换,则不清楚比较是否旨在测试f
是否保留从d
复制时将保留的值,或者d
是否保留从f
复制时将保留的值。限制使用带重载的隐式转换……会让编译器在有意义的时候执行隐式转换,在没有意义的地方发出嘎嘎声。我认为如果选项同时起作用,在不破坏兼容性的情况下,行为可能会得到改进