让我们假设我们在groovy中有一个函数作为参数BigDecimal
:
void func(BigDecimal bd) {...}
在groovy var.func(0)
这工作正常,但在java中它根本不会编译。我知道BigDecimal
中有一个构造函数可以用于Integer
,但是这个在groovy和java中工作的原因是什么呢?
是否存在将def
变量转换为java中已知变量的内容?
答案 0 :(得分:1)
当您调用值与声明类型不同的方法时,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(20)
调用替换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));
方法,因此没有类型强制,您必须传递有效类型。