java - 在 Groovy 中将整数转换为 BigDecimal

标签 java groovy

假设我们在 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/

相关文章:

java - 如何根据 POJO 中的另一个值更改变量的值?

java - 如何使用maven执行groovy文件?

grails - Grails外部Jms代理(事件MQ)

jquery - 在Grails Controller 中使用g.render的输出

java - Jsoup java重写它应该添加的文件字符串

java - 在Eclipse中运行mapreduce程序时出错

java - 双重检查锁定 (DCL) 及其修复方法

java - 在 AllegroGraph 中注册命名空间(缺少注册的命名空间。)

xml - 具有相同元素标签但数据唯一的XML解析

groovy - 如何将 Email-Ext groovy 脚本放置在 jenkins 文件系统上