“可能的有损转换”是什么意思,我该如何解决?

时间:2018-08-01 11:30:05

标签: java compiler-errors

新的Java程序员经常被诸如以下的编译错误消息所迷惑:

  

“不兼容的类型:可能从双精度转换为整数”

对于这一行代码:

int squareRoot = Math.sqrt(i);

此错误是什么意思,以及如何解决?

1 个答案:

答案 0 :(得分:18)

首先,这是一个编译错误。如果您在运行时在异常消息中看到它,那是因为您运行的程序存在编译错误 1

消息的一般形式是:

  

“不兼容的类型:可能从 <type1> <type2> 的有损转换”

其中 <type1> <type2> 都是原始数字类型;即bytecharshortintlongfloatdouble中的一个。

当您的代码尝试进行从 <type1> <type2> 隐式转换时,会发生此错误,但是转换可能是有损

在问题示例中:

  int squareRoot = Math.sqrt(i);

sqrt方法产生一个double,但是从doubleint的转换可能会造成损失。

“潜在损失”是什么意思?

让我们看几个例子。

  1. long转换为int可能会造成损失,因为存在long值没有相应的int值。例如,任何大于2 ^ 31-1的long值太大而无法表示为int。同样,任何小于-2 ^ 31的数字都太小。

  2. int转换为long不会造成有损转换,因为每个int值都有一个对应的long值。

    li>
  3. float转换为long可能会造成损失,因为其中float的值太大或太小而不能表示为long值。

  4. long转换为float不会造成有损转换,因为每个long值都有一个对应的float值。 (转换后的值可能不太精确,但是在这种情况下,“有损”并不意味着...。)

所有这些转换都可能会造成损失:

  • shortbytechar
  • charbyteshort
  • intbyteshortchar
  • longbyteshortcharint
  • floatbyteshortcharintlong
  • doublebyteshortcharintlongfloat

如何解决该错误?

使编译错误消失的方法是添加类型转换。例如;

  int i = 47;
  int squareRoot = Math.sqrt(i);         // compilation error!

成为

  int i = 47;
  int squareRoot = (int) Math.sqrt(i);   // no compilation error

但这真的可以解决吗?考虑47的平方根是6.8556546004 ...,但是squareRoot将得到值6。 (转换将截断,而不是舍入。)

那呢?

  byte b = (int) 512;

这导致b获得值0。从较大的int类型转换为较小的int类型是通过屏蔽高阶位来完成的,512的低阶8位全为零。

简而言之,您不应简单地添加类型转换,因为它可能无法为您的应用程序正确地完成

相反,您需要了解为什么代码需要进行转换:

  • 发生这种情况是因为您在代码中犯了其他错误吗?
  • <type1> 应该是其他类型,这样在这里不需要有损转换吗?
  • 如果需要进行转换,那么是否为 silent 有损转换,即类型转换将执行正确的行为?
  • 还是您的代码应该进行一些范围检查并通过引发异常来处理不正确/意外的值?

某些特定情况:

下标时出现“可能的有损转换”。

第一个示例:

for (double d = 0; d < 10.0; d += 1.0) {
    System.out.println(array[d]);  // <<-- possible lossy conversion
}

这里的问题是数组索引值必须为int。因此必须将ddouble转换为int。通常,将浮点值用作索引没有意义。有人可能会认为Java数组的工作方式类似于(例如)Python字典,或者他们忽略了浮点算术通常不精确的事实。

解决方案是重写代码,以避免将浮点值用作数组索引。 (添加类型转换可能是不正确的解决方案。)

第二个示例:

for (long l = 0; l < 10; l++) {
    System.out.println(array[l]);  // <<-- possible lossy conversion
}

这是先前问题的一个变体,解决方案相同。区别在于,根本原因是Java数组限制为32位索引。如果您想要一个具有2个以上 31 -1个元素的“数组式”数据结构,则需要定义或查找一个类来实现。


1-例如,Eclipse IDE有一个选项,使您可以忽略编译错误并始终运行代码。如果选择此选项,则IDE的编译器将创建一个.class文件,如果调用该文件,则带有错误的方法将引发未经检查的异常。异常消息将提及编译错误消息。