0

目前我正在研究一种以字符串形式运行java代码的方法。所以这就是我的做法。

import java.util.HashMap;
import java.util.Map;

import groovy.lang.GroovyClassLoader;

public class GroovyStackOverflow {

    public static void main(String[] args) {
        GroovyClassLoader gcl = new GroovyClassLoader();
        String codeSnippet = "double calculatedAnswer = (Double)"
                + "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
                + " calculatedAnswer = Math.sqrt(calculatedAnswer); "
                + "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
                + "System.out.println(calculatedAnswer);"
                + " return calculatedAnswer;";
        StringBuilder sb = new StringBuilder();
        sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
        sb.append(codeSnippet);
        sb.append("} }");
        Class<?> clazz = gcl.parseClass(sb.toString());
        ScriptEvaluator scriptEvaluator = null;     
        double calculatedAnswer = 100.0;        
        try {
            Map contextMap = new HashMap();
            contextMap.put("doubleValue", (double)100.0);
            contextMap.put("threadId", "thread"+100);
            contextMap.put("hashCode", 100);
            scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
            scriptEvaluator.evaluate(contextMap);;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

public interface ScriptEvaluator {
    public Object evaluate(Map contextMap);
}

问题是它在以下情况下失败。

import java.util.HashMap;
import java.util.Map;

import groovy.lang.GroovyClassLoader;

public class GroovyStackOverflow {

    public static void main(String[] args) {
        GroovyClassLoader gcl = new GroovyClassLoader();
        String codeSnippet = "double calculatedAnswer = (Double)"
                + "\n "
                + "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
                + " calculatedAnswer = Math.sqrt(calculatedAnswer); "
                + "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
                + "System.out.println(calculatedAnswer);"
                + " return calculatedAnswer;";
        StringBuilder sb = new StringBuilder();
        sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
        //sb.append(codeSnippet.replaceAll("\n", " "));
        sb.append(codeSnippet);
        sb.append("} }");
        Class<?> clazz = gcl.parseClass(sb.toString());
        ScriptEvaluator scriptEvaluator = null;     
        double calculatedAnswer = 100.0;
        try {
            Map contextMap = new HashMap();
            contextMap.put("doubleValue", (double)100.0);
            contextMap.put("threadId", "thread"+100);
            contextMap.put("hashCode", 100);
            scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
            scriptEvaluator.evaluate(contextMap);;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
public interface ScriptEvaluator {
    public Object evaluate(Map contextMap);
}

我不明白为什么它会失败以及此错误消息的含义-

Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class java.lang.Double' with class 'java.lang.Class' to class 'double'
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToNumber(DefaultTypeTransformation.java:163)
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.doubleUnbox(DefaultTypeTransformation.java:88)
    at ScriptImplementor.evaluate(script15126616543572010791987.groovy:1)
    at GroovyStackOverflow.main(GroovyStackOverflow.java:33)

取消注释此代码后//sb.append(codeSnippet.replaceAll("\n", " "));,它可以工作。但请提出更好的处理方法。还有为什么它在解析类时不出错?我还能期待这样的其他惊喜吗?

4

1 回答 1

3

您发现了 Java 和 Groovy 之间的差异。

在 Java 中,语句以分号结束。

在 Groovy 中,语句以分号结束,如果语句已经是完整语句,则以换行符结束

在您的情况下,这意味着代码

double calculatedAnswer = (Double)
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")

是两个陈述。

这些语句中的第一个是double calculatedAnswer = (Double).

在 Groovy 中,您也可以省略.class引用类,因此Double.class可以写为Double.

因此,您在该语句中所做的就是将Double类对象分配给一个double变量。括号在这里只是无操作。

这当然会像消息中所说的那样失败,因为Double类对象不能自动区分大小写double

您可以显式地转义换行符,使其不会像 in 那样结束语句

double calculatedAnswer = (Double)\
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")

这会像你预期的那样工作。

但当然也可能存在 Groovy 和 Java 不同的其他情况。

永远记住,Groovy 语法与 Java 语法很接近,但并不完全相同。

Afair each valid Java code is also valid Groovy code, but not necessarily with the exact same meaning as you can see in this example.

于 2017-12-07T17:09:13.360 回答