这将产生127
double middle = 255 / 2
虽然产量为127.5
Double middle = 255 / 2
与此同时产生127.5
double middle = (255 / 2) as double
我知道Groovy默认使用BigDecimal进行操作,但是对我来说这是一个Huuge错误!怎么会这样?
答案 0 :(得分:2)
这实际上与BigDecimals
无关,而是与从原始整数到原始double的类型强制转换无关。该问题是由Groovy编译器及其生成的(很可能是)不正确的字节码引起的。看一下以下第一种情况的字节码表示。以下Groovy代码:
void ex1() {
double x = 255 / 2
println x
}
被编译为字节码,可以表示为:
public void ex1() {
CallSite[] var1 = $getCallSiteArray();
double x = 0.0D;
if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigD() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) {
int var5 = 255 / 2;
x = (double)var5;
} else {
Object var4 = var1[5].call(255, 2);
x = DefaultTypeTransformation.doubleUnbox(var4);
}
var1[6].callCurrent(this, x);
}
这表明在这种情况下,不可能获得127.5
的结果,因为255 / 2
表达式的结果存储在类型int
的变量中。感觉这是行为不一致的一个示例,因为这是使用Double
的方法的字节码的样子:
public void ex2() {
CallSite[] var1 = $getCallSiteArray();
Double x = null;
if (BytecodeInterface8.isOrigInt() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) {
Object var4 = var1[8].call(255, 2);
x = (Double)ScriptBytecodeAdapter.castToType(var4, Double.class);
} else {
Object var3 = var1[7].call(255, 2);
x = (Double)ScriptBytecodeAdapter.castToType(var3, Double.class);
}
var1[9].callCurrent(this, x);
}
该用例的主要问题是添加@TypeChecked
不会阻止您犯此错误-编译通过并返回错误的结果。但是,当我们在使用@TypeChecked
的方法中添加Double
注释时,会引发编译错误。添加@CompileStatic
可解决问题。
我已经进行了一些测试,并且可以确认最近的 2.5.6 和 3.0.0-alpha-4 版本中都存在此问题。 I've created a bug report在Groovy JIRA项目中。感谢您发现并报告问题!
似乎这不是Groovy的错误-Java也是如此。在Java中,您可以在double变量中存储两个整数的除法结果,但是除了将整数强制转换为double以外,您什么都不会得到。使用{{Double}}类型在语法方面有所不同,但在字节码方面却非常相似。使用{{Double}},您需要将等式的至少一部分显式转换为{{double}}类型,这将导致将两个整数都转换为{{double}}的字节码。考虑下面的Java示例:
final class IntDivEx {
static double div(int a, int b) {
return a / b;
}
static Double div2(int a, int b) {
return a / (double) b;
}
public static void main(String[] args) {
System.out.println(div(255,2));
System.out.println(div2(255,2));
}
}
运行它会得到:
127.0
127.5
现在,如果您查看它创建的字节码,您将看到类似这样的内容:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
final class IntDivEx {
IntDivEx() {
}
static double div(int a, int b) {
return (double)(a / b);
}
static Double div2(int a, int b) {
return (double)a / (double)b;
}
public static void main(String[] args) {
System.out.println(div(255, 2));
System.out.println(div2(255, 2));
}
}
Groovy与Java之间的唯一区别(就语法而言)是Groovy允许您将整数隐式转换为Double
,这就是为什么
Double x = 255 / 2
是Groovy中的正确语句,而在这种情况下,Java在编译过程中失败,并出现以下错误:
Error:(10, 18) java: incompatible types: int cannot be converted to java.lang.Double
这就是为什么在Java中,当您将整数分配给Double
时,需要使用强制转换。