利用javax.tools动态编译执行java代码

  inkfish原创,请勿商业性质转载,转载请注明来源(http://blog.csdn.net/inkfish

)。

  参考:使用 javax.tools 创建动态应用程序

 

  javax.tools 包是一种添加到 Java SE 6 的标准 API,可以实现 Java 源代码编译,使您能够添加动态功能来扩展静态应用程序。本文将探查javax.tools包中提供的主要类,以Java表达式表示计算一个数值函数y=x*x+x。更多详情请参考《使用 javax.tools 创建动态应用程序》和javax.tools API docs

 

complier.CharSequenceCompiler源码:

package complier;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* 编译{@link CharSequence}形式的源码,并实例化,返回一个实例。<br>
* 用法示例(以编译MyInterface的一个实现类为例):
*
* <pre>
* MyInterface instance = null;
* JavaStringCompiler<MyInterface> compiler = new JavaStringCompiler<MyInterface>(null, null);
* try {
* Class<MyInterface> newClass = compiler.compile("com.mypackage.NewClass",
* stringContaininSourceForNewClass, new Class<?>[] { MyInterface.class });
* instance = newClass.newInstance();
* } catch (JavaStringCompilerException ex) {
* ex.printStackTrace();
* } catch (IllegalAccessException ex) {
* ex.printStackTrace();
* }
* instance.someOperation(someArgs);
* </pre>
*/
public class CharSequenceCompiler<T> {
/** 真正使用的编译器 */
private final JavaCompiler compiler;
private final ClassLoaderImpl classLoader;
/** 保存编译器编译中的诊断信息 */
private DiagnosticCollector<JavaFileObject> diagnostics;
private final FileManagerImpl javaFileManager;
/** 编译参数 */
private final List<String> options;
/**
* 构造一个新的实例,该实例持有指定的classloader
*
* @param loader
* 应用的{@link ClassLoader}
* @param options
* 编译器的编译参数,具体可参考javac编译参数
* @throws IllegalStateException
* 如果java编译器不能正确载入则抛出异常
*/
public CharSequenceCompiler(ClassLoader loader, Collection<String> options) {
compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
throw new IllegalStateException("系统java编译器无法找到,请确认类路径中已经包含tools.jar(注:JDK 6中默认自带,JRE 6中默认不带)。");
}
if (loader == null) {
classLoader = new ClassLoaderImpl(this.getClass().getClassLoader());
} else {
classLoader = new ClassLoaderImpl(loader);
}
this.options = new ArrayList<String>();
if (options != null) {
this.options.addAll(options);
}
diagnostics = new DiagnosticCollector<JavaFileObject>();
javaFileManager = new FileManagerImpl(compiler.getStandardFileManager(diagnostics, null, Charset
.forName(Utils.ENCODING)), classLoader);
}
/**
* 编译多个Java类的源码
*
* @param classes
* key为类的完全限定名,value为对应的源码。
* @return 编译后的类
* @throws CharSequenceCompilerException
*/
public synchronized Map<String, Class<T>> compile(Map<String, CharSequence> classes)
throws CharSequenceCompilerException {
//准备待编译文件
List<JavaFileObject> sources = new ArrayList<JavaFileObject>();
for (Entry<String, CharSequence> entry : classes.entrySet()) {
String qualifiedClassName = entry.getKey();
CharSequence javaSource = entry.getValue();
if (javaSource != null) {
int dotPos = qualifiedClassName.lastIndexOf('.');
String className = dotPos == -1 ? qualifiedClassName : qualifiedClassName
.substring(dotPos + 1);
String packageName = dotPos == -1 ? "" : qualifiedClassName.substring(0, dotPos);
JavaFileObjectImpl source = new JavaFileObjectImpl(className, javaSource);
sources.add(source);
javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName, className
+ ".java", source);
}
}
//编译代码
CompilationTask task = compiler.getTask(null, javaFileManager, diagnostics, options, null, sources);
Boolean result = task.call();
//返回编译结果
if ((result == null) || !result.booleanValue()) {
throw new CharSequenceCompilerException("Compilation failed.", classes.keySet(), diagnostics);
}
try {
Map<String, Class<T>> compiled = new HashMap<String, Class<T>>();
for (String qualifiedClassName : classes.keySet()) {
compiled.put(qualifiedClassName, loadClass(qualifiedClassName));
}
return compiled;
} catch (ClassNotFoundException ex) {
throw new CharSequenceCompilerException(classes.keySet(), ex, diagnostics);
} catch (IllegalArgumentException ex) {
throw new CharSequenceCompilerException(classes.keySet(), ex, diagnostics);
} catch (SecurityException ex) {
throw new CharSequenceCompilerException(classes.keySet(), ex, diagnostics);
}
}
/**
* 编译一个Java类。
*
* @param qualifiedClassName
* 类的完全限定名。
* @param javaSource
* 编译的java类完整的源码。
* @param types
* 0或多个类,用以检验被编译的类能否转换成这些类中任何一个。
* @return 编译后的类
* @throws CharSequenceCompilerException
* 如果类无法被编译则抛出异常。
* @throws ClassCastException
* 如果编译后的类无法转换成types中的任何一种类型,则抛出异常。
*/
public synchronized Class<T> compile(String qualifiedClassName, CharSequence javaSource,
Class<?>... types) throws CharSequenceCompilerException, ClassCastException {
diagnostics = new DiagnosticCollector<JavaFileObject>();
Map<String, CharSequence> classes = new HashMap<String, CharSequence>(1);
classes.put(qualifiedClassName, javaSource);
Map<String, Class<T>> compiled = compile(classes);
Class<T> newClass = compiled.get(qualifiedClassName);
for (Class<?> type : types) {
if (!type.isAssignableFrom(newClass)) {
throw new ClassCastException(type.getName());
}
}
return newClass;
}
/** 载入Java类。 */
@SuppressWarnings("unchecked")
private Class<T> loadClass(final String qualifiedClassName) throws ClassNotFoundException {
return (Class<T>) classLoader.loadClass(qualifiedClassName);
}
}

 

complier.CharSequenceCompilerException源码:

package complier;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
@SuppressWarnings("serial")
public class CharSequenceCompilerException extends Exception {
/** 所有被编译的类的完整类名 */
private Set<String> classNames;
transient private DiagnosticCollector<JavaFileObject> diagnostics;
public CharSequenceCompilerException(Set<String> qualifiedClassNames, Throwable cause,
DiagnosticCollector<JavaFileObject> diagnostics) {
super(cause);
setClassNames(qualifiedClassNames);
setDiagnostics(diagnostics);
}
public CharSequenceCompilerException(String message, Set<String> qualifiedClassNames,
DiagnosticCollector<JavaFileObject> diagnostics) {
super(message);
setClassNames(qualifiedClassNames);
setDiagnostics(diagnostics);
}
public CharSequenceCompilerException(String message, Set<String> qualifiedClassNames, Throwable cause,
DiagnosticCollector<JavaFileObject> diagnostics) {
super(message, cause);
setClassNames(qualifiedClassNames);
setDiagnostics(diagnostics);
}
/** @return 返回编译出问题的类的全名称 */
public Collection<String> getClassNames() {
return Collections.unmodifiableSet(classNames);
}
/** 得到异常的诊断信息 */
public DiagnosticCollector<JavaFileObject> getDiagnostics() {
return diagnostics;
}
private void setClassNames(Set<String> qualifiedClassNames) {
classNames = new HashSet<String>(qualifiedClassNames);
}
private void setDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics) {
this.diagnostics = diagnostics;
}
}

 

complier.ClassLoaderImpl源码:

package complier;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaFileObject;
import org.apache.commons.io.IOUtils;
/** {@link ClassLoader}的一个实现,它map类名和JavaFileObjectImpl的实例。本类在{@link CharSequenceCompiler}和{@link FileManagerImpl}中被使用。 */
final class ClassLoaderImpl extends ClassLoader {
private final Map<String, JavaFileObjectImpl> classes = new HashMap<String, JavaFileObjectImpl>();
ClassLoaderImpl(final ClassLoader parentClassLoader) {
super(parentClassLoader);
}
@Override
public InputStream getResourceAsStream(final String name) {
if (name.endsWith(".class")) {
String qualifiedClassName = name.substring(0, name.length() - ".class".length())
.replace('/', '.');
JavaFileObjectImpl file = classes.get(qualifiedClassName);
if (file != null) {
try {
return new ByteArrayInputStream(IOUtils.toByteArray(file.openInputStream()));
} catch (IOException ex) {
}
}
}
return super.getResourceAsStream(name);
}
protected void add(final String qualifiedClassName, final JavaFileObjectImpl javaFile) {
classes.put(qualifiedClassName, javaFile);
}
/** @return 返回不可变的Collection,含有所有持有的{@link JavaFileObject}对象 */
protected Collection<JavaFileObjectImpl> files() {
return Collections.unmodifiableCollection(classes.values());
}
@Override
protected Class<?> findClass(final String qualifiedClassName) throws ClassNotFoundException {
JavaFileObject file = classes.get(qualifiedClassName);
if (file != null) {
try {
byte[] bytes = IOUtils.toByteArray(file.openInputStream());
return defineClass(qualifiedClassName, bytes, 0, bytes.length);
} catch (IOException ex) {
}
}
// Workaround in Java 6. see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6434149
try {
Class<?> c = Class.forName(qualifiedClassName);
return c;
} catch (ClassNotFoundException nf) {
}
return super.findClass(qualifiedClassName);
}
@Override
protected synchronized Class<?> loadClass(final String name, final boolean resolve)
throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
}

 

complier.FileManagerImpl源码:

package complier;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.JavaFileObject.Kind;
/**
* {@link JavaFileManager}的一个实例,用于管理Java源代码和byte code。<br>
* 所有的源码以{@link CharSequence}的形式保存在内存中,byte code以byte数组形式存放在内存中。
*/
final class FileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
private final ClassLoaderImpl classLoader;
private final Map<URI, JavaFileObject> fileObjects = new HashMap<URI, JavaFileObject>();
FileManagerImpl(JavaFileManager fileManager, ClassLoaderImpl classLoader) {
super(fileManager);
this.classLoader = classLoader;
}
@Override
public ClassLoader getClassLoader(JavaFileManager.Location location) {
return classLoader;
}
@Override
public FileObject getFileForInput(Location location, String packageName, String relativeName)
throws IOException {
FileObject o = fileObjects.get(uri(location, packageName, relativeName));
if (o != null) {
return o;
}
return super.getFileForInput(location, packageName, relativeName);
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, Kind kind,
FileObject outputFile) throws IOException {
JavaFileObjectImpl file = new JavaFileObjectImpl(qualifiedName, kind);
classLoader.add(qualifiedName, file);
return file;
}
@Override
public String inferBinaryName(Location loc, JavaFileObject file) {
String result;
if (file instanceof JavaFileObjectImpl) {
result = file.getName();
} else {
result = super.inferBinaryName(loc, file);
}
return result;
}
@Override
public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds,
boolean recurse) throws IOException {
Iterable<JavaFileObject> result = super.list(location, packageName, kinds, recurse);
ArrayList<JavaFileObject> files = new ArrayList<JavaFileObject>();
if ((location == StandardLocation.CLASS_PATH) && kinds.contains(JavaFileObject.Kind.CLASS)) {
for (JavaFileObject file : fileObjects.values()) {
if ((file.getKind() == Kind.CLASS) && file.getName().startsWith(packageName)) {
files.add(file);
}
}
files.addAll(classLoader.files());
} else if ((location == StandardLocation.SOURCE_PATH) && kinds.contains(JavaFileObject.Kind.SOURCE)) {
for (JavaFileObject file : fileObjects.values()) {
if ((file.getKind() == Kind.SOURCE) && file.getName().startsWith(packageName)) {
files.add(file);
}
}
}
for (JavaFileObject file : result) {
files.add(file);
}
return files;
}
void putFileForInput(StandardLocation location, String packageName, String relativeName,
JavaFileObject file) {
fileObjects.put(uri(location, packageName, relativeName), file);
}
private URI uri(Location location, String packageName, String relativeName) {
return Utils.toURI(new StringBuilder(location.getName()).append('/').append(packageName).append('/')
.append(relativeName).toString());
}
}

 

complier.JavaFileObjectImpl源码:

package complier;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
/**
* {@link FileObject}和{@link JavaFileObject}的一个实现,它能持有java源代码或编译后的class。这个类可以用于:
* <ol>
* <li>存放需要传递给编译器的源码,这时使用的是{@link JavaFileObjectImpl#JavaFileObjectImpl(String, CharSequence)}构造器。</li>
* <li>存放编译器编译完的byte code,这是使用的是{@link JavaFileObjectImpl#JavaFileObjectImpl(String, JavaFileObject.Kind)}</li>
* </ol>
*/
final class JavaFileObjectImpl extends SimpleJavaFileObject {
/** 如果kind == CLASS, 存储byte code,可以通过{@link #openInputStream()}得到 */
private ByteArrayOutputStream byteCode;
/** 如果kind == SOURCE, 存储源码 */
private final CharSequence source;
/**
* 创建持有源码的实例
*
* @param baseName
* the base name
* @param source
* the source code
*/
JavaFileObjectImpl(final String baseName, final CharSequence source) {
super(Utils.toURI(baseName + ".java"), Kind.SOURCE);
this.source = source;
}
/**
* 创建持有二进制byte code的实例
*
* @param name
* the file name
* @param kind
* the kind of file
*/
JavaFileObjectImpl(final String name, final Kind kind) {
super(Utils.toURI(name), kind);
source = null;
}
@Override
public CharSequence getCharContent(final boolean ignoreEncodingErrors)
throws UnsupportedOperationException {
if (source == null) {
throw new UnsupportedOperationException("getCharContent()");
}
return source;
}
@Override
public InputStream openInputStream() {
return new ByteArrayInputStream(byteCode.toByteArray());
}
@Override
public OutputStream openOutputStream() {
return (byteCode = new ByteArrayOutputStream());
}
@Override
public Writer openWriter() throws IOException {
return new OutputStreamWriter(openOutputStream(), Utils.ENCODING);
}
}

 

complier.Utils源码:

package complier;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
public abstract class Utils {
public static final String ENCODING = Charset.defaultCharset().name();
/** 把String转换成URI,如果转换异常不抛出URISyntaxException,而直接抛出RuntimeException。 */
static URI toURI(String name) {
try {
return new URI(name);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}

 

  以上代码为complier包中所有类,它对外暴露的主要方法是:CharSequenceCompiler<T>.compile(String qualifiedClassName, CharSequence javaSource, Class<?>... types) throws CharSequenceCompilerException, ClassCastException,通过它来动态编译字符串形式表示的java源代码。除此之外,包中其他方类和方法尽量使用默认访问权限,以避免他人误用以及隐藏实现细节。

  下面是测试package中的内容:

 

complier.test.Function源码:定义了一个接口,动态编译的所有类实现这个接口。

package complier.test;
public interface Function {
double doFunction(double x);
}

 

complier.test.Function实现类的模板,方便类的生成。

package $packageName;
import static java.lang.Math.*;
public class $className implements complier.test.Function {
@Override
public double doFunction(double x){
return $expression;
}
}

 

complier.test.ExpressionCal源码:里面含有一个静态测试类ExpressionCal$Tester。

package complier.test;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Random;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import complier.CharSequenceCompiler;
import complier.CharSequenceCompilerException;
import complier.Utils;
public class ExpressionCal {
/** 包名前缀 */
private static final String PACKAGE_NAME = "javaxtools.compiler.test.runtime";
public static class Tester {
public static void main(String[] args) throws ScriptException {
//第一遍测试
test();
System.out.println("------Test Twice------/n");
test();
}
public static void test() throws ScriptException {
DecimalFormat df = new DecimalFormat("0.00");
int loop = 10 * 10000 - 1;
String exp = "x*x+x";
double d = new Random().nextDouble() * 100;
long start;
//直接计算
start = System.nanoTime();
for (int i = 0; i < loop; i++) {
@SuppressWarnings("unused")
double a = d * d + d;
}
System.out.printf(exp.replace("x", df.format(d)) + "=%2.4f/n", d * d + d);
System.out.printf("Time of direct cal %d loops: %10.2f微秒./n/n", loop + 1,
(System.nanoTime() - start) / 1000d);
//编译源码并计算
start = System.nanoTime();
Function func = new ExpressionCal().newFunction(exp);
System.out.printf("Java src complain time: %10.2f微秒, /t", (System.nanoTime() - start) / 1000d);
start = System.nanoTime();
for (int i = 0; i < loop; i++) {
func.doFunction(d);
}
System.out.printf(exp.replace("x", df.format(d)) + "=%2.4f/n", func.doFunction(d));
System.out.printf("Complained source %d loops: %10.2f微秒./n/n", loop + 1,
(System.nanoTime() - start) / 1000d);
//内置Javascript计算
start = System.nanoTime();
ScriptEngine se = new ScriptEngineManager().getEngineByName("ECMAScript");
CompiledScript script = ((Compilable) se).compile("var x;" + exp);
System.out.printf("JS complain time: %10.2f微秒, /t", (System.nanoTime() - start) / 1000d);
start = System.nanoTime();
Bindings binding = new SimpleBindings();
for (int i = 0; i < loop; i++) {
binding.put("x", d);
script.eval(binding);
}
binding.put("x", d);
System.out.printf(exp.replace("x", df.format(d)) + "=%2.4f/n", script.eval(binding));
System.out.printf("Javascript %d loops: %10.2f微秒./n", loop + 1,
(System.nanoTime() - start) / 1000d);
}
}
/** 类名后缀 */
private int classNameSuffix = 0;
/** 随机数生成器,用于生成随机的包名和类名 */
private static final Random random = new Random();
/** 字符串形式的Java源文件内容 */
private String template;
private static final String TEMPLATE_NAME = "Function.java.template";
private static final String TARGET_VERSION = "1.6";
private final CharSequenceCompiler<Function> compiler = new CharSequenceCompiler<Function>(getClass()
.getClassLoader(), Arrays.asList(new String[] { "-target", TARGET_VERSION, "-encoding",
Utils.ENCODING }));
public Function newFunction(String expr) {
StringBuilder errStr = new StringBuilder();
Function result = null;
try {
//生成唯一的包名和类名
final String packageName = PACKAGE_NAME + digits();
final String className = "C_" + (classNameSuffix++) + digits();
final String qName = packageName + '.' + className;
//生成类的源码
final String source = fillTemplate(packageName, className, expr);
//编译源码
Class<Function> compiledFunction = compiler.compile(qName, source,
new Class<?>[] { Function.class });
result = compiledFunction.newInstance();
} catch (CharSequenceCompilerException ex) {
errStr.append(log(ex.getDiagnostics()));
ex.printStackTrace();
} catch (InstantiationException ex) {
errStr.append(ExceptionUtils.getFullStackTrace(ex)).append("/n");
ex.printStackTrace();
} catch (IllegalAccessException ex) {
errStr.append(ExceptionUtils.getFullStackTrace(ex)).append("/n");
ex.printStackTrace();
} catch (IOException ex) {
errStr.append(ExceptionUtils.getFullStackTrace(ex)).append("/n");
ex.printStackTrace();
}
if (errStr.toString().trim().length() > 0) {
System.err.println(errStr.toString());
}
return result;
}
/** @return 返回以'_'开头的随机16进制字符串 */
private String digits() {
return '_' + Long.toHexString(random.nextLong());
}
/**
* 生成字符串形式的java源文件内容
*
* @param packageName
* 包名
* @param className
* 类名
* @param expression
* 表达式
* @return 字符串形式的java源文件内容
* @throws IOException
*/
private String fillTemplate(String packageName, String className, String expression) throws IOException {
if (template == null) {
template = IOUtils.toString(Function.class.getResourceAsStream(TEMPLATE_NAME), Utils.ENCODING);
}
String source = template.replace("$packageName", packageName)//
.replace("$className", className)//
.replace("$expression", expression);
return source;
}
/** 记录{@link DiagnosticCollector}中的错误内容 */
private CharSequence log(final DiagnosticCollector<JavaFileObject> diagnostics) {
final StringBuilder msgs = new StringBuilder();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
msgs.append(diagnostic.getMessage(null)).append("/n");
}
return msgs;
}
}

 

ExpressionCal$Tester测试表达式x*x+x的运行,具体测试直接计算、java编译并计算、javascript编译并计算的效率,共测试三遍以观察其效率的变化,每一遍中每种方法又用for循环运行10万次计算,忽略打印输出的耗时。测试时间使用微秒为单位,精确度取决于System.nanoTime(),详见其java docs中的说明。测试结果如下:

44.53*44.53+44.53=2027.7451
Time of direct cal 100000 loops: 6461.72微秒.
Java src complain time: 604570.13微秒, 44.53*44.53+44.53=2027.7451
Complained source 100000 loops: 5412.14微秒.
JS complain time: 23354.09微秒, 44.53*44.53+44.53=2027.7451
Javascript 100000 loops: 8671081.10微秒.
------Test twice------
7.67*7.67+7.67=66.4529
Time of direct cal 100000 loops: 670.48微秒.
Java src complain time: 44715.18微秒, 7.67*7.67+7.67=66.4529
Complained source 100000 loops: 1397.38微秒.
JS complain time: 2375.44微秒, 7.67*7.67+7.67=66.4529
Javascript 100000 loops: 8493123.29微秒.
------Test third times------
74.34*74.34+74.34=5600.4535
Time of direct cal 100000 loops: 572.14微秒.
Java src complain time: 39487.42微秒, 74.34*74.34+74.34=5600.4535
Complained source 100000 loops: 1375.04微秒.
JS complain time: 1867.56微秒, 74.34*74.34+74.34=5600.4535
Javascript 100000 loops: 8624124.85微秒.

 

整理得到:

10万次计算

(单位:毫秒)

直接计算 java编译并计算 JS编译并计算
编译 计算 编译 计算
第一遍 6.46 604.57 5.41 23.35 8671.08
第二遍 0.67 44.71 1.4 2.38 8493.12
第三遍 0.57 39.49 1.38 1.87 8624.12

 

  可以看出,java直接计算速度超快,java编译并计算速度还是比直接计算慢1倍(不计编译时间),而JS的计算速度比直接计算慢4个数量级,简直惨不忍睹。第一次运行除JS计算外,均比较耗时,其中java第一次编译需要从磁盘上读取template文件,以后则均为内存操作。

  从测试结果看,如果需要运行一个固定的表达式,可以写死在Java程序中(废话),如果需要计算一个动态变化的表达式,如果计算次数较少(500次以下),JS较为划算,如果计算次数十分巨大,则需要考虑java编译并计算。

时间: 2024-12-04 00:34:49

利用javax.tools动态编译执行java代码的相关文章

页面上有个textarea,在里面写java代码,然后如何动态编译执行这段java代码??

问题描述 页面上有个textarea,在里面写java代码,然后如何动态编译执行这段java代码?? 页面上有个textarea,在里面写java代码,然后如何动态编译执行这段java代码?? 解决方案 可以使用一些前端的模板引擎,java是编译的 解决方案二: ajax提交客户端输入的代码动态执行就行,看下面参考 ajax提交http://www.w3school.com.cn/jquery/ java中怎么执行字符串中的代码http://bbs.csdn.net/topics/3903563

J2EE里JSP页面如何执行java代码???

问题描述 J2EE里JSP页面如何执行java代码??? 以下是java代码: package servlet; import java.io.IOException; import java.io.PrintWriter; import java.sql.ResultSet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpSe

Android 利用 APT 技术在编译期生成代码_Android

APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入.现在有很多主流库都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等,我们要紧跟潮流,与时俱进呐! (ง •̀_•́)ง 下面通过一个简单的 View 注入项目 ViewFinder 来介绍 APT 相关内容,简单实现了类似于ButterKnife 中的两种注解 @BindView 和 @OnClick . 项目

Android 利用 APT 技术在编译期生成代码

APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入.现在有很多主流库都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等,我们要紧跟潮流,与时俱进呐! (ง •̀_•́)ง 下面通过一个简单的 View 注入项目 ViewFinder 来介绍 APT 相关内容,简单实现了类似于ButterKnife 中的两种注解 @BindView 和 @OnClick . 项目

语法分析 编译-动态分析java代码结构

问题描述 动态分析java代码结构 首先非常感谢您来到这里, 我最近需要实现一个功能模块,这个模块的功能和ecplise的大纲视图类似. 用户在JTextArea中连续编码,程序需要动态分析用户当前正在编辑的类,通过一个树形结构来显示这个类的结构. 这个树形结构以类名为根,根下节点为类属性和方法,甚至内部类,当用户键入一个新的成员时,就在树中插入一个相应的节点. 我只是一个大三学生,这个任务对我来说实在有点困难,所以希望得到您的指点或者创意. 我接收到的想法有: 1.通过JDK中提供的API实现

如何让EditPlus可以编译执行Java程序

编译|程序|执行 在 USER TOOLS中选:Add Tool>>1.配置JAVACMenu Text:javacCommand:C:\jdk1.3.1\in\javac.exeArgument:$(FileName)Initial Derictory:$(FileDir)选中 Capture output2.配置JAVAMenu Text:javaCommand:C:\jdk1.3.1\in\java.exeArgument:$(FileNameNoExt)Initial Derictor

MAC 系统如何使用 Sublime Text 2 直接编译运行 java 代码_java

修改 /Users/$username/Library/Application Support/Sublime Text 2/Packages/Java/JavaC.sublime-build 为: 复制代码 代码如下: {  "cmd": ["java", "$file_base_name"],  "file_regex": "^ *\\[javac\\] (.+):([0-9]+):() (.*)$",

动态编译JAVA程序

编译|程序|动态 在Sun JDK 1.2及后续版本中,包含了一组可在程序运行时刻编译和执行Java代码的API.这些API被包含在tools.jar类库中.这个功能允许Java程序在运行时动态编译.执行小的代码块,在有些情况下这个功能会让Java应用程序的架构更加灵活.开放. 本文假定读者已经在计算机中安装并配置好了Sun JDK 1.2或更高的版本,并对javac编译器命令有所了解. 在Java程序中使用编译器 假定要使用javac命令编译 /home/mytest目录下Test.java文

Java理论与实践: 动态编译与性能测量

这个月,我着手撰写一篇文章,分析一个写得很糟糕的微评测.毕竟,我们 的程序员一直受性能困扰,我们也都想了解我们编写.使用或批评的代码的性能 特征.当我偶然间写到性能这个主题时,我经常得到这样的电子邮件:"我写的 这个程序显示,动态 frosternation 要比静态 blestification 快,与您上一 篇的观点相反!"许多随这类电子邮件而来的所谓"评测"程序,或者它们运行 的方式,明显表现出他们对于 JVM 执行字节码的实际方式缺乏基本认识.所以 ,在我着