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

新的Java程序员经常会被编译错误消息搞糊涂,例如:

“不兼容的类型:从double到int的可能有损转换”

对于这行代码:

int squareRoot = Math.sqrt(i); 

这个错误意味着什么,你如何解决它?

首先,这是一个编译错误。 如果你在运行时在exception消息中看到它,那是因为你已经运行了一个带有编译错误的程序1

消息的一般forms是:

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

其中都是原始数字类型; 即bytecharshortintlongfloatdouble

当您的代码尝试从进行隐式转换但转换可能有损时会发生此错误。

在问题中的示例中:

  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值。

  3. float转换为long是一种潜在的有损转换,因为float值太大或太小而不能表示为long值。

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

这些都是可能有损的转换:

  • shortbytechar
  • charbyteshort
  • intbyteshortchar
  • long to byteshortcharint
  • float to byteshortcharintlong
  • double to byteshortcharintlongfloat

你如何解决这个错误?

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

  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位全部为零。

简而言之,您不应该简单地添加类型转换,因为它可能无法为您的应用程序执行正确的操作。

相反,您需要了解代码需要进行转换的原因:

  • 这是因为您在代码中犯了其他错误吗?
  • 应该是不同的类型,这样就不需要有损转换吗?
  • 如果转换是必要的,那么类型转换会做出正确行为的静默有损转换吗?
  • 或者您的代码是否应该进行一些范围检查并通过抛出exception来处理错误/意外值?

一些具体案例:

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

第一个例子:

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

这里的问题是数组索引值必须是int 。 所以d必须从double转换为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文件,其中带有错误的方法将在调用时抛出未经检查的exception。 exception消息将提及编译错误消息。