在Groovy中将Integer转换为BigDecimal

时间:2018-01-17 07:51:08

标签: java groovy

让我们假设我们在groovy中有一个函数作为参数BigDecimal

 void func(BigDecimal bd) {...}

在groovy var.func(0)

的其他课程中再次调用它

这工作正常,但在java中它根本不会编译。我知道BigDecimal中有一个构造函数可以用于Integer,但是这个在groovy和java中工作的原因是什么呢? 是否存在将def变量转换为java中已知变量的内容?

1 个答案:

答案 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));方法,因此没有类型强制,您必须传递有效类型。