如何从Java中的字符串创建对象(如何评估字符串)?
我知道eval是“邪恶的”,但我以一种用户永远不会滥用它的方式使用它。如何从Java中的字符串创建对象(如何评估字符串)?
假设我有一个字符串“new Integer(5)”。我想做一些事情,让我可以设置一个变量,让我们说foo,新的整数(5)。像
Integer foo;
String bar = "new Integer(5)"
*magic happens*
System.out.println(foo) -> 5
我环顾四周,它看起来像我有几个选项。 ToolProvider中的getSystemJavaCompiler()方法可以执行此操作吗?或者我应该使用BeanShell?或者还有别的吗?请注意,这是来自一个字符串,而不是一个文件。
我会用一个脚本语言一样的BeanShell,JRuby的,Jython中,等
的Integer class需要在其构造函数来设置值的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());
}
这是一个例子,我在寻找一个通用的解决方案 – swampsjohn 2009-07-23 00:44:56
Java是一种静态类型语言,所以我认为你不能这样做。
这种事情是可能的,但对于像这样简单的任务来说,这将是非常昂贵的。在这个例子中,我会考虑使用Class.forName()将“Integer”映射到类,并且Java反射会调用构造函数。
以下是通过使用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<JavaFileObject> tasks = new ArrayList<JavaFileObject>();
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<String> 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<JavaFileObject> list(JavaFileManager.Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException { return parent.list(location, packageName, kinds, recurse); }
public int isSupportedOption(String option) { return parent.isSupportedOption(option); }
}
}
我认为用户会'滥用'eval的恐惧不是主要的罪恶。在大多数情况下,程序员滥用eval。在像Java这样的强类型语言中,eval只会让维护程序员感到困惑。 – Josiah 2009-07-23 00:19:13
你为什么想这样做。我可以想到没有真正的情况,这将是有用的。我想你有一个XY问题。 – Raedwald 2014-12-10 13:03:08