我不明白为什么代码片段1工作正常,但代码片段2给出编译时错误incompatible types: java.lang.Long cannot be converted to int
和java中强制转换的优先级有关吗?我在stackoverflow上浏览了这条线索,但无济于事。
请详细解释这两个代码段中的幕后情况,以及为什么它在代码段1中没有出现错误。
代码片段1:
package com.company;
public class Main
{
public static void main(String[] args)
{
double dbl = 10.25;
int i1 = (int)Math.round(dbl);
}
}
代码片段2:
package com.company;
public class Main
{
public static void main(String[] args)
{
double dbl = 10.25;
Long lng = Math.round(dbl);
int i2 = (int)lng;
}
}
让我们仔细看看会发生什么。在片段1中:
double dbl = 10.25;
int i1 = (int) Math.round(dbl);
您声明了double
。四舍五入后的结果是long
。然后是对int
的强制转换,这是可能的,因为两者都是基元类型,Java允许强制转换。然后将其存储在int
中。
在片段2中,情况有所变化:
double dbl = 10.25;
Long lng = Math.round(dbl);
int i2 = (int) lng;
您声明了一个double
,round返回了long
,但您希望将其存储在Long
中。因此,Java自动将long
转换为Long
,这被称为自动装箱。Java可以将所有基元类型封装到它们的包装器类中。
最后,您尝试将Long
强制转换为int
,但这是不可能的,因为Long
现在是一个对象。但是,它可以自动取消对Long
到long
的装箱。从那里你可以去int
。让我们先来看看这两种变体:
int i2 = (long) lng; // Make unboxing explicit by casting
int i2 = lng.longValue() // Use unboxing method
然而,由于以下原因,它也不会编译:
不兼容类型:从long到int 的可能有损转换
因此转换是可能的,但编译器警告我们,long
可能不适合int
(有损转换),因此它阻止我们这样做。
然而,我们可以通过再次使其显式来进行转换:
int i2 = (int) lng.longValue() // The whole process completely explicit
或者,如果您有Java 8,请使用Math#toIntExact
(文档),如果long
不适合int
:,它将抛出ArithmeticException
int i2 = Math.toIntExact(lng.longValue());
请注意,Java不会自动将Long
取消装箱为long
,然后将其强制转换为int
,您需要自己明确取消装箱,如图所示。
这只是JVM的强制转换规则之一,在这种情况下可能是为了防止无意的编程错误。