在Java 1.8.0_152中使用Math.round(双d)时强制转换为int



我不明白为什么代码片段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现在是一个对象。但是,它可以自动取消对Longlong的装箱。从那里你可以去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强制转换规则之一,在这种情况下可能是为了防止无意的编程错误。

最新更新