假设我们在 groovy 中有一个函数将 BigDecimal
作为参数:
void func(BigDecimal bd) {...}
然后在 groovy 的其他类中再次调用它 var.func(0)
这工作正常,但在 java 中它根本无法编译。我知道 BigDecimal
中有一个构造函数适用于 Integer
,但它在 groovy 中有效并且 java 提示它的原因是什么?
是否有将 def
变量转换为 java 中已知的东西?
最佳答案
当您使用不同于声明类型的值调用方法时,Groovy 使用参数类型强制。如果是 BigDecimal
参数类型强制 Groovy 使用 BigDecimalCachedClass.coerceArgument(Object argument)
方法:
public Object coerceArgument(Object argument) {
if (argument instanceof BigDecimal) {
return argument;
} else if (argument instanceof Long) {
return new BigDecimal((Long) argument);
} else if (argument instanceof BigInteger) {
return new BigDecimal((BigInteger) argument);
}
if (argument instanceof Number) {
return new BigDecimal(((Number) argument).doubleValue());
}
return argument;
}
当您将 Integer
作为参数传递时,if (argument instanceof Number)
分支得到满足,Groovy 将输入 Integer 转换为其 BigDecimal
代表。
它在 Java 中不起作用,因为 Java 不是动态语言,所以所有类型都必须在编译时解析。 Groovy 支持动态类型,因此您的最终类型可以在运行时解析。
@CompileStatic
和@TypeChecked
Groovy 允许您关闭它的动态特性。如果您使用 @CompileStatic
或 @TypeChecked
注释您的类,那么调用 var.func(0)
将不再有效,因为 Groovy 将不再使用它的动态特性。
考虑以下简单的 Groovy 类:
class NumTest {
static void main(String[] args) {
test(20)
}
static void test(BigDecimal number) {
println number
}
}
当你用 groovyc
编译它时,你会看到一个像这样的 Java 类:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import java.math.BigDecimal;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class NumTest implements GroovyObject {
public NumTest() {
CallSite[] var1 = $getCallSiteArray();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].callStatic(NumTest.class, Integer.valueOf(20));
}
public static void test(BigDecimal number) {
CallSite[] var1 = $getCallSiteArray();
var1[1].callStatic(NumTest.class, number);
}
}
有趣的是,调用 test(20)
不是直接的静态方法调用,而是:
var1[0].callStatic(NumTest.class, Integer.valueOf(20));
但是如果我们用 @CompileStatic
注释我们的类,它将不再编译,我们将不得不用直接 test( BigDecimal.valueOf(20))
调用:
import groovy.transform.CompileStatic
@CompileStatic
class NumTest {
static void main(String[] args) {
test(BigDecimal.valueOf(20))
}
static void test(BigDecimal number) {
println number
}
}
用groovyc
编译这个类生成完全不同的Java类:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import java.math.BigDecimal;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
public class NumTest implements GroovyObject {
public NumTest() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public static void main(String... args) {
test(BigDecimal.valueOf((long)20));
Object var10000 = null;
}
public static void test(BigDecimal number) {
DefaultGroovyMethods.println(NumTest.class, number);
Object var10000 = null;
}
}
这里可以看到直接调用了test(BigDecimal.valueOf((long)20));
方法,所以没有类型强制,必须传递有效类型到位。
关于java - 在 Groovy 中将整数转换为 BigDecimal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48296049/