如何用Java中的字符串创建对象(如何评估字符串)?

我知道eval是“邪恶的”,但我正以一种用户不能滥用它的方式使用它。

假设我有一个字符串“new Integer(5)”。 我想做一些事情,我可以设置一个变量,比如说foo,给新的Integer(5)。 就像是

Integer foo; String bar = "new Integer(5)" *magic happens* System.out.println(foo) -> 5 

我环顾四周,看起来我有几个选择。 ToolProvider中的getSystemJavaCompiler()方法可以这样做吗? 或者我应该使用BeanShell? 或者还有其他什么? 请注意,这是来自字符串,而不是文件。

我会使用像beanshell,jruby,jython等脚本语言。

你必须使用像Janino这样的东西。

这是通过使用javax.tools获得大部分方法的可能方法。 请注意,此代码相当长,并不是最有效或最便携的方法,但您应该明白这一点。

 import javax.tools.*; import java.util.*; import java.io.*; import java.lang.reflect.*; public class Test { public static void main(String[] args) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaFileObject fileObj = new StringJavaFileObject("public class InterpTest { public static void test() { System.out.println(\"Hello World\"); } }"); List tasks = new ArrayList(); tasks.add(fileObj); JavaFileManager defFileMgr = compiler.getStandardFileManager(null, null, null); MemoryJavaFileManager fileMgr = new MemoryJavaFileManager(defFileMgr); compiler.getTask(null, fileMgr, null, null, null, tasks).call(); ClassLoader loader = new ByteArrayClassLoader(); Class clazz = loader.loadClass("InterpTest"); Method method = clazz.getMethod("test"); method.invoke(null); } public static class StringJavaFileObject extends SimpleJavaFileObject { protected String str; public StringJavaFileObject(String str) { super(java.net.URI.create("file:///InterpTest.java"), JavaFileObject.Kind.SOURCE); this.str = str; } @Override public CharSequence getCharContent(boolean ignoreEncErrors) { return str; } } public static class MemoryJavaFileObject extends SimpleJavaFileObject { public static ByteArrayOutputStream out = new ByteArrayOutputStream(); public MemoryJavaFileObject(String uri, JavaFileObject.Kind kind) { super(java.net.URI.create(uri), kind); } @Override public OutputStream openOutputStream() { return out; } } public static class ByteArrayClassLoader extends ClassLoader { public Class findClass(String name) { byte[] bytes = MemoryJavaFileObject.out.toByteArray(); return super.defineClass(name, bytes, 0, bytes.length); } } public static class MemoryJavaFileManager implements JavaFileManager { protected JavaFileManager parent; public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { return new MemoryJavaFileObject("file:///InterpTest.class", kind); } public MemoryJavaFileManager(JavaFileManager parent) { this.parent = parent; } public void close() throws IOException { parent.close(); } public void flush() throws IOException { parent.flush(); } public ClassLoader getClassLoader(JavaFileManager.Location location) { return parent.getClassLoader(location); } public FileObject getFileForInput(JavaFileManager.Location location, String packageName, String relName) throws IOException { return parent.getFileForInput(location, packageName, relName); } public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relName, FileObject sibling) throws IOException { return parent.getFileForOutput(location, packageName, relName, sibling); } public JavaFileObject getJavaFileForInput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind) throws IOException { return parent.getJavaFileForInput(location, className, kind); } public boolean handleOption(String current, Iterator remaining) { return parent.handleOption(current, remaining); } public boolean hasLocation(JavaFileManager.Location location) { return parent.hasLocation(location); } public String inferBinaryName(JavaFileManager.Location location, JavaFileObject file) { return parent.inferBinaryName(location, file); } public boolean isSameFile(FileObject a, FileObject b) { return parent.isSameFile(a, b); } public Iterable list(JavaFileManager.Location location, String packageName, Set kinds, boolean recurse) throws IOException { return parent.list(location, packageName, kinds, recurse); } public int isSupportedOption(String option) { return parent.isSupportedOption(option); } } } 

这种事情是可能的,但对于像这样简单的任务来说,这将是非常昂贵的。 在这个例子中,我考虑使用Class.forName()将“Integer”映射到一个类,Javareflection调用Constructor。

假设提供的字符串仅包含数字文本, Integer类在其构造函数中采用String来设置值。

 Integer foo; public void setFoo(String str) { if(isInt(str)) { foo = new Integer(str.trim()); } } // Returns a boolean based on if the provided string contains only numbers private boolean isInt(String str) { boolean isInt = true; try { Integer.parseInt(str.trim()); } catch (NumberFormatException nfe) { isInt = false; } return isInt; } // Get the value as an int rather than Integer public int getIntValue(String str) { return Integer.parseInt(str.trim()); } 

Java是一种静态类型语言,所以我认为你不能这样做。

您可以使用Java Scripting API 。 默认语言是JavaScript,但您可以插入任何语言。 但它需要java 1.6。