新的Java程序员经常对编译错误消息感到困惑,例如:
“不兼容的类型:从double到int的可能有损转换”
对于这行代码:
int squareRoot = Math.sqrt(i);
这个错误意味着什么,你如何解决它?
发布于 2019-06-14 09:38:39
首先,这是一个编译错误。如果你在运行时在异常消息中看到它,那是因为你运行了一个带有编译错误的程序1。
消息的一般形式是:
“不兼容的类型:可能有损转换
<type1>
为<type2>
”
where <type1>
和<type2>
都是原始数字类型; 的即,一个byte
,char
,short
,int
,long
,float
或double
。
当你的代码试图做一个发生这种错误的隐式从转换<type1>
到<type2>
但转换可能是有损耗的。
在问题中的示例中:
int squareRoot = Math.sqrt(i);
该sqrt
方法产生double
,而是从一个转换double
到int
具有潜在的损耗。
那么让我们看看几个例子。
long
到一个int
是一个潜在的有损转换,因为有long
不具有一个相应的值int
的值。例如,任何long
大于2 ^ 31 - 1的值都太大而无法表示为int
。同样,任何小于-2 ^ 31的数字都太小。int
到a的long
转换不是有损转换,因为每个int
值都有相应的long
值。float
到一个long
是一个潜在的有损转换,因为有float
值过大或过小,无法表示为long
数值。long
到a的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类型的转换,并且低阶8位512
全部为零。
简而言之,您不应该简单地添加类型转换,因为它可能无法为您的应用程序执行正确的操作。
相反,您需要了解代码需要进行转换的原因:
<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
文件,其中带有错误的方法将在调用时抛出未经检查的异常。异常消息将提及编译错误消息。
https://stackoverflow.com/questions/-100005193
复制相似问题