【问题标题】:Run code from a string in Java [duplicate]从Java中的字符串运行代码[重复]
【发布时间】:2013-07-12 06:03:07
【问题描述】:

出于调试原因,我希望能够运行通过控制台输入的代码。例如:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while(true){
    String str = br.readLine(); //This can return 'a = 5;','b = "Text";' or 'pckg.example.MyClass.run(5);'
    if(str == null)
        return;
    runCode(str); //How would I do this?
}

【问题讨论】:

  • 真正的问题是:为什么你想这样做...
  • 让我们暂时假设这是可能的......但是想想Java将如何编译您的运行时代码?
  • 您需要的可能是Java interpreter
  • +1 交互式 Java 控制台?我有点喜欢这个主意。
  • @couling 它不应该是为什么?,它应该是为什么哦,为什么有人会这样做?拜托,这似乎就像暴行一样。

标签: java


【解决方案1】:

请不要实际使用它

我假设您想将字符串评估为 Java 代码,而不是像 Javascript 这样的脚本引擎,所以 在阅读this 后,我使用提到的编译器 API 标记一时兴起创建了这个。这可能是非常糟糕的做法,但它(有点)就像你想要的那样工作。我怀疑它在调试中会有多大用处,因为它在新类的上下文中运行代码。示例用法包含在底部。

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

public class main {
    public static void runCode(String s) throws Exception{
        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);
        File jf = new File("test.java"); //create file in current working directory
        PrintWriter pw = new PrintWriter(jf);
        pw.println("public class test {public static void main(){"+s+"}}");
        pw.close();
        Iterable fO = sjfm.getJavaFileObjects(jf);
        if(!jc.getTask(null,sjfm,null,null,null,fO).call()) { //compile the code
            throw new Exception("compilation failed");
        }
        URL[] urls = new URL[]{new File("").toURI().toURL()}; //use current working directory
        URLClassLoader ucl = new URLClassLoader(urls);
        Object o= ucl.loadClass("test").newInstance();
        o.getClass().getMethod("main").invoke(o);

    }
    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            try {
            String str = br.readLine(); //This can return 'a = 5;','b = "Text";' or 'pckg.example.MyClass.run(5);'
            if(str == null)
                return;

            runCode(str); //How would I do this?
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

    }
}
//command line
>  System.out.println("hello");
hello
>  System.out.println(3+2+3+4+5+2);
19
>  for(int i = 0; i < 10; i++) {System.out.println(i);}
0
1
2
3
4
5
6
7
8
9

使用SimpleJavaFileObject,您实际上可以避免使用文件,如here 所示,但语法似乎有点麻烦,所以我只选择了当前工作目录中的文件。

编辑Convert String to Code 提供了类似的方法,但还没有完全充实

【讨论】:

    【解决方案2】:

    如果代码在 JavaScript 中,那么您可以使用 JavaScript 引擎运行它:

    Object res = new ScriptEngineManager().getEngineByName("js").eval(str);
    

    自 1.6 以来,JavaScript 引擎是 Java SE 的一部分。详情请参阅本指南http://download.java.net/jdk8/docs/technotes/guides/scripting/programmer_guide/index.html

    【讨论】:

    • 还有其他脚本语言,如BeanShell、java子集。
    • 如果脚本是选项,那么为什么要远离java?有 Scala、Groovy 和 JRuby,似乎每个人都喜欢 JRuby 的性能。
    • 如果您使用的是 java8,我会使用 nudge4j lorenzoongithub.github.io/nudge4j
    【解决方案3】:

    您可以使用位于包javax.script 中的Java 脚本API。您可以在其中包含多种脚本语言,例如 bsh

    您可以在Oracle的网页上找到programmer's guide

    Rhino,它是某种 JavaScript,已经包含在 Oracle JVM 中。

    【讨论】:

      【解决方案4】:

      为此,您可能需要查看Java Compiler API。我没有研究过它是如何工作的,但是它允许你加载一个 java 文件,在一个已经运行的系统中编译和加载类。也许它可以重新用于接受来自控制台的输入。

      【讨论】:

      • 这个方法意味着创建一个文件,编写类和代码,编译它,打开它,运行代码......这似乎不是运行一行代码的最佳方式.. .
      【解决方案5】:

      对于通用编译器,您可以使用Janino,这将允许您编译和运行 Java 代码。 expression evaluator 可能对您的示例有所帮助。

      如果您只是想在调试时评估表达式,那么 Eclispe 有 Display view 允许您执行表达式。见this question

      【讨论】:

        猜你喜欢
        • 2016-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-20
        • 2012-12-10
        相关资源
        最近更新 更多