新的Java程序员经常被诸如以下的编译错误消息所迷惑:
“不兼容的类型:可能从双精度转换为整数”
对于这一行代码:
int squareRoot = Math.sqrt(i);
此错误是什么意思,以及如何解决?
答案 0 :(得分:18)
首先,这是一个编译错误。如果您在运行时在异常消息中看到它,那是因为您运行的程序存在编译错误 1 。
消息的一般形式是:
“不兼容的类型:可能从
<type1>
到<type2>
的有损转换”
其中 <type1>
和 <type2>
都是原始数字类型;即byte
,char
,short
,int
,long
,float
或double
中的一个。
当您的代码尝试进行从 <type1>
到 <type2>
的隐式转换时,会发生此错误,但是转换可能是有损。
在问题示例中:
int squareRoot = Math.sqrt(i);
sqrt
方法产生一个double
,但是从double
到int
的转换可能会造成损失。
让我们看几个例子。
将long
转换为int
可能会造成损失,因为存在long
值没有相应的int
值。例如,任何大于2 ^ 31-1的long
值太大而无法表示为int
。同样,任何小于-2 ^ 31的数字都太小。
将int
转换为long
不会造成有损转换,因为每个int
值都有一个对应的long
值。
将float
转换为long
可能会造成损失,因为其中float
的值太大或太小而不能表示为long
值。
将long
转换为float
不会造成有损转换,因为每个long
值都有一个对应的float
值。 (转换后的值可能不太精确,但是在这种情况下,“有损”并不意味着...。)
所有这些转换都可能会造成损失:
short
至byte
或char
char
至byte
或short
int
至byte
,short
或char
long
至byte
,short
,char
或int
float
至byte
,short
,char
,int
或long
double
至byte
,short
,char
,int
,long
或float
。使编译错误消失的方法是添加类型转换。例如;
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>
应该是其他类型,这样在这里不需要有损转换吗?下标时出现“可能的有损转换”。
第一个示例:
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
文件,如果调用该文件,则带有错误的方法将引发未经检查的异常。异常消息将提及编译错误消息。