`
zhangziyangup
  • 浏览: 1187171 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

简介

javax.tools 包是一种添加到 Java SE 6 的标准 API,可以实现 Java 源代码编译,使您能够添加动态功能来扩展静态应用程序。本文将探查 javax.tools 包中提供的主要类,并演示如何使用它们创建一个 façade,以从 Java StringStringBuffer 或其他 CharSequence 中编译 Java 源代码,而不是从文件中编译。之后,使用这个 façade 构建一个交互式绘图应用程序,通过该应用程序,用户可以使用任何有效的数值 Java 表达式表示一个数值函数 y = f(x)。最后,本文将讨论与动态源代码编译相关的安全风险以及应对方法。

通 过编译和加载 Java 扩展来对应用程序进行扩展,这种想法并不新鲜,并且一些现有框架也支持这一功能。Java Platform, Enterprise Edition (Java EE) 中的 JavaServer Pages (JSP) 技术就是一种广为人知的动态框架,能够生成并编译 Java 类。JSP 转换器通过中间产物即源代码文件将 .jsp 文件转换为 Java servlet,JSP 引擎随后将源代码文件编译并加载到 Java EE servlet 容器中。编译过程通常是通过直接调用 javac 编译器完成的,这需要安装 Java Development Kit (JDK) 或者调用 com.sun.tools.javac.Main(可通过 Sun 的 tools.jar 获得)。Sun 的许可证允许跟随完整的 Java 运行时环境(Java Runtime Environment,JRE)一起重新分发 tools.jar。其他实现动态功能的方法包括使用可与应用程序实现语言(参见 参考资料)集成的现有动态脚本编制语言(例如 JavaScript 或 Groovy),或者编写特定于域的语言和相关的语言解释器和编译器。

其 他框架(例如 NetBeans 和 Eclipse)支持开发人员使用 Java 语言直接编写扩展,但是这些框架需要外部静态编译,并需要管理 Java 代码及其工件的源代码和二进制文件。Apache Commons JCI 提供了一种机制可以将 Java 类编译并加载到运行的应用程序中。Janino 和 Javassist 也提供了类似的动态功能,但是 Janino 只限于 Java 1.4 之前的语言,而 Javassist 只能工作在 Java 类抽象级别,而不能在源代码级别工作(参见 参考资料 中有关这些项目的链接)。然而,Java 开发人员已经熟悉如何使用 Java 语言编写程序,如果一种系统能够动态生成 Java 源代码并进行编译和加载,那么它可以保证最短的学习曲线并提供最大程度的灵活性。

使用 javax.tools 的优点

使用 javax.tools 具有以下好处:

  • 它是经过认可的 Java SE 扩展,这意味着它是 Java Community Process(按照 JSR 199 规范)开发的标准 API。com.sun.tools.javac.Main API 不属于 经过文件归档的 Java 平台 API,因此没有必要在其他供应商的 JDK 中提供或保证在未来版本的 Sun JDK 中提供该 API。

  • 您可以应用已经掌握的知识:Java 源代码,而不是字节码。不需要学习生成有效字节码的复杂规则或者新的类对象模型、方法、语句和表达式,通过生成有效的 Java 源代码,您就可以创建正确的 Java 类。

  • 它简化了一种受支持机制,并进行了标准化,使您不用局限于基于文件的源代码就可生成并加载代码。

  • 它可以在 JDK Version 6 和更高版本的各种供应商实现之间移植,并且将来也支持这种移植性。

  • 它使用经过验证的 Java 编译器。

  • 与基于解释器的系统不同,所加载的类可以从 JRE 的运行时优化中受益。

Java 编译:概念和实现

要理解 javax.tools 包,回顾 Java 编译概念以及如何使用包实现编译将非常有帮助。javax.tools 包以一种通用的方式对这些概念进行了抽象化,使您能够从备用的源代码对象提供源代码,而不要求源代码必须位于文件系统中。

编译 Java 源代码需要用到以下组件:

  • 类路径,编译器从其中解析库类。编译器类路径通常由一个有序的文件系统目录列表和一些归档文件(JAR 或 ZIP 文件)组成,归档文件中包含先前编译过的 .class 文件。类路径由一个 JavaFileManager 实现,后者管理多个源代码和类 JavaFileObject 实例以及传递给 JavaFileManager 构造函数的 ClassLoaderJavaFileObject 是一个 FileObject,专门处理以下任一种由编译器使用的 JavaFileObject.Kind 枚举类型:
    • SOURCE
    • CLASS
    • HTML
    • OTHER
    每个源文件提供一个 openInputStream() 方法,可以作为 InputStream访问源代码。

  • javac 选项,以 Iterable<String> 的形式传递

  • 源文件 — 待编译的一个或多个 .java 源文件。JavaFileManager 提供了一个抽象的文件系统,可以将源文件和输出文件的文件名映射到 JavaFileObject 实例(其中,文件 表示一个惟一名称和一串字节之间的关联。客户机不需要使用实际的文件系统)。在本文的示例中,JavaFileManager 管理类名与 CharSequence 实例之间的映射,后者包含待编译的 Java 源代码。JavaFileManager.Location 包含一个文件名和一个标记,该标记可以表明该位置是源代码还是一个输出位置。 ForwardingJavaFileManager 实现 Chain of Responsibility 模式(参见 参考资料),允许将文件管理器链接在一起,就像类路径和源路径将 JAR 和目录链接起来一样。如果在这条链的第一个元素中没有发现 Java 类,那么将对链中的其他元素进行查找。

  • 输出目录,编译器在其中编写生成的 .class 文件。作为输出类文件的集合,JavaFileManager 也保存表示编译过的 CLASS 文件的 JavaFileObject 实例。

  • 编译器JavaCompiler 创建 JavaCompiler.CompilationTask 对象,后者从 JavaFileManager 中的 JavaFileObject SOURCE 对象编译源代码,创建新的输出 JavaFileObject CLASS 文件和 Diagnostic(警告和错误)。静态 ToolProvider.getSystemJavaCompiler() 方法返回编译器实例。

  • 编译器警告和错误,这些内容通过 DiagnosticDiagnosticListener 实现。Diagnostic 是编译器发出的警告或编译错误。Diagnostic 指定以下内容:
    • KindERRORWARNINGMANDATORY_WARNINGNOTEOTHER
    • 源代码中的位置(包括行号和列号)
    • 消息
    客户机向编译器提供一个 DiagnosticListener,编译器可通过它向客户机发回诊断信息。DiagnosticCollector 是一个简单的 DiagnosticListener 实现。

图 1 展示了 javax.tools 中的 javac 概念与其实现之间的映射:


图 1. javac 概念如何映射到 javax.tools 接口
javac 概念如何映射到 javax.tools 接口。

了解了这些概念,我们现在看一下如何实现一个 façade 来编译 CharSequence


编译 CharSequence 实例中的 Java 源代码

在本节中,我将为 javax.tools.JavaCompiler 构造一个 façade。javaxtools.compiler.CharSequenceCompiler 类(参见 下载)可以编译保存在任何 java.lang.CharSequence 对象(例如 StringStringBufferStringBuilder)中的 Java 源代码,并返回一个 ClassCharSequenceCompiler 提供了以下 API:

  • public CharSequenceCompiler(ClassLoader loader, Iterable<String> options) :该构造函数接收传递给 Java 编译器的 ClassLoader,允许它解析相关类。Iterable options 允许客户机传递额外的编译器选项,这些选项均对应于 javac 选项。

  • public Map<String, Class<T>> compile(Map<String, CharSequence> classes, final DiagnosticCollector<JavaFileObject> diagnostics) throws CharSequenceCompilerException, ClassCastException :这是常用的编译方法,支持同时编译多个源代码。注意,Java 编译器必须处理类的循环依赖性,例如 A.java 依赖 B.java,B.java 依赖 C.java,而 C.java 又依赖 A.java。该方法的第一个参数是 Map,它的键为完全限定类名,而相应的值为包含该类源代码的 CharSequence。例如:
    • "mypackage.A""package mypackage; public class A { ... }";
    • "mypackage.B""package mypackage; class B extends A implements C { ... }";
    • "mypackage.C""package mypackage; interface C { ... }"
    编译器将 Diagnostic 添加到 DiagnosticCollector。您希望对类进行强制转换的主要类型是泛型类型参数 Tcompile() 被另一个方法重载,其参数为一个类名和待编译的 CharSequence

  • public ClassLoader getClassLoader() :该方法返回编译器在生成 .class 文件时组装的类加载器,因此,可以从其中加载其他类或资源。

  • public Class<T> loadClass(final String qualifiedClassName) throws ClassNotFoundException :由于 compile() 方法可以定义多个类(包括公共的嵌套类),因此允许加载辅助类。

为了支持 CharSequenceCompiler API,我使用 JavaFileObjectImpl 类和 JavaFileManagerImpl 实现了 javax.tools 接口,其中,JavaFileObjectImpl 类用于保存 CharSequence 源代码和编译器产生的 CLASS 输出,而 JavaFileManagerImpl 用于将名称映射到 JavaFileObjectImpl 实例,从而管理源代码和编译器产生的字节码。

JavaFileObjectImpl

清单 1 中的 JavaFileObjectImpl 实现 JavaFileObject 并保存 CharSequence source(用于 SOURCE)或一个 ByteArrayOutputStream byteCode(用于 CLASS 文件)。关键方法是 CharSequence getCharContent(final boolean ignoreEncodingErrors),编译器通过它获得源代码文本。参见 下载,获取所有代码示例的源代码。


清单 1. JavaFileObjectImpl(只显示部分源代码)

FileManagerImpl

FileManagerImpl(参见清单 2)对 ForwardingJavaFileManager 进行了扩展,将限定的类名映射到 JavaFileObjectImpl 实例:


清单 2. FileManagerImpl(只显示部分源代码)

CharSequenceCompiler

如果 ToolProvider.getSystemJavaCompiler() 不能创建 JavaCompiler

如果 tools.jar 不在应用程序类路径中,ToolProvider.getSystemJavaCompiler() 方法可以返回 nullCharStringCompiler 类检测到这一配置问题后将抛出一个异常,并给出修复建议。注意,Sun 许可证允许跟随 JRE 一起重新分发 tools.jar。

通过这些支持类,现在可以定义 CharSequenceCompiler,可使用运行时 ClassLoader 和编译器选项构建。它使用 ToolProvider.getSystemJavaCompiler() 获得 JavaCompiler 实例,然后对转发给编译器标准文件管理器的 JavaFileManagerImpl 进行实例化。

compile() 方法对输入映射进行迭代,从每个名称/CharSequence 中构建一个 JavaFileObjectImpl,并将其添加到 JavaFileManager 中,因此,在调用文件管理器的 getFileForInput() 方法时,JavaCompiler 将找到它们。compile() 方法随后将创建一个 JavaCompiler.Task 实例并运行该实例。故障被作为 CharSequenceCompilerException 抛出。然后,对于传递给 compile() 方法的所有源代码,加载产生的 Class 类并放在结果 Map 中。

CharSequenceCompiler (参见清单 3)相关的类加载器是一个 ClassLoaderImpl 实例,它在 JavaFileManagerImpl 实例中查找类的字节码,返回编译器创建的 .class 文件:


清单 3. CharSequenceCompiler(只显示部分源代码)
publicclassCharSequenceCompiler<T>...{
privatefinalClassLoaderImplclassLoader;
privatefinalJavaCompilercompiler;
privatefinalList<String>options;
privateDiagnosticCollector<JavaFileObject>diagnostics;
privatefinalFileManagerImpljavaFileManager;

publicCharSequenceCompiler(ClassLoaderloader,Iterable<String>options)...{
compiler
=ToolProvider.getSystemJavaCompiler();
if(compiler==null)...{
thrownewIllegalStateException(
"CannotfindthesystemJavacompiler."
+"Checkthatyourclasspathincludestools.jar");
}

classLoader
=newClassLoaderImpl(loader);
diagnostics
=newDiagnosticCollector<JavaFileObject>();
finalJavaFileManagerfileManager=compiler.getStandardFileManager(diagnostics,
null,null);
javaFileManager
=newFileManagerImpl(fileManager,classLoader);
this.options=newArrayList<String>();
if(options!=null)...{
for(Stringoption:options)...{
this.options.add(option);
}

}

}


publicsynchronizedMap<String,Class<T>>
compile(
finalMap<String,CharSequence>classes,
finalDiagnosticCollector<JavaFileObject>diagnosticsList)
throwsCharSequenceCompilerException,ClassCastException...{
List
<JavaFileObject>sources=newArrayList<JavaFileObject>();
for(Entry<String,CharSequence>entry:classes.entrySet())...{
StringqualifiedClassName
=entry.getKey();
CharSequencejavaSource
=entry.getValue();
if(javaSource!=null)...{
finalintdotPos=qualifiedClassName.lastIndexOf('.');
finalStringclassName=dotPos==-1
?qualifiedClassName
:qualifiedClassName.substring(dotPos
+1);
finalStringpackageName=dotPos==-1
?""
:qualifiedClassName.substring(
0,dotPos);
finalJavaFileObjectImplsource=
newJavaFileObjectImpl(className,javaSource);
sources.add(source);
javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH,packageName,
className
+".java",source);
}

}

finalCompilationTasktask=compiler.getTask(null,javaFileManager,diagnostics,
options,
null,sources);
finalBooleanresult=task.call();
if(result==null||!result.booleanValue())...{
thrownewCharSequenceCompilerException("Compilationfailed.",
classes.keySet(),diagnostics);
}

try...{
Map
<String,Class<T>>compiled=
newHashMap<String,Class<T>>();
for(Entry<String,CharSequence>entry:classes.entrySet())...{
StringqualifiedClassName
=entry.getKey();
finalClass<T>newClass=loadClass(qualifiedClassName);
compiled.put(qualifiedClassName,newClass);
}

returncompiled;
}
catch(ClassNotFoundExceptione)...{
thrownewCharSequenceCompilerException(classes.keySet(),e,diagnostics);
}
catch(IllegalArgumentExceptione)...{
thrownewCharSequenceCompilerException(classes.keySet(),e,diagnostics);
}
catch(SecurityExceptione)...{
thrownewCharSequenceCompilerException(classes.keySet(),e,diagnostics);
}

}

}

Plotter 应用程序

现在,我有了一个可以编译源代码的简单 API,我将通过创建函数绘制应用程序(使用 Swing 编写)来发挥其功用。图 2 展示了该应用程序使用图形表示 x * sin(x) * cos(x) 函数:


图 2. 使用 javaxtools.compiler 包的动态应用程序
Plotter Swing 应用程序屏幕截图

该应用程序使用清单 4 中定义的 Function 接口:


清单 4. Function 接口
应用程序提供了一个文本字段,用户可以向其中输入一个 Java 表达式,后者根据隐式声明的 double x 输入参数返回一个 double 值。在清单 5 所示的代码模板中,应用程序将表达式文本插入到以 $expression 标记的位置。并且每次生成一个惟一的类名,替代模板中的 $className。包名也是一个模板变量。
清单 5. Function 模板

应用程序使用 fillTemplate(packageName, className, expr) 函数填充模板,它返回一个 String 对象,然后应用程序使用 CharSequenceCompiler 进行编译。异常或编译器诊断信息被传递给 log() 方法或直接写入到应用程序中可滚动的 errors 组件。

清单 6 显示的 newFunction() 方法将返回一个对象,它将实现 Function 接口(参见 清单 5 中的源代码模板):


清单 6. PlotterFunction newFunction(String expr) 方法

FunctionnewFunction(finalStringexpr)...{
errors.setText(
"");
try...{
//generatesemi-secureuniquepackageandclassnames
finalStringpackageName=PACKAGE_NAME+digits();
finalStringclassName="Fx_"+(classNameSuffix++)+digits();
finalStringqName=packageName+'.'+className;
//generatethesourceclassasString
finalStringsource=fillTemplate(packageName,className,expr);
//compilethegeneratedJavasource
finalDiagnosticCollector<JavaFileObject>errs=
newDiagnosticCollector<JavaFileObject>();
Class
<Function>compiledFunction=stringCompiler.compile(qName,source,errs,
newClass<?>[]...{Function.class});
log(errs);
returncompiledFunction.newInstance();
}
catch(CharSequenceCompilerExceptione)...{
log(e.getDiagnostics());
}
catch(InstantiationExceptione)...{
errors.setText(e.getMessage());
}
catch(IllegalAccessExceptione)...{
errors.setText(e.getMessage());
}
catch(IOExceptione)...{
errors.setText(e.getMessage());
}

returnNULL_FUNCTION;
}

您通常会生成一些源类,使用它们扩展已有的基类或实现特定接口,从而可以将实例转换为已知的类型并通过一个类型安全 API 调用其方法。注意,在实例化 CharSequenceCompiler<T> 时,Function 类被作为泛型类型参数 T 使用。因此,也可以将 compiledFunction 输入作为 Class<Function>compiledFunction.newInstance(),以返回 Function 实例,而不需要进行强制转换。

动态生成一个 Function 实例后,应用程序使用它针对一系列 x 值生成 y 值,然后使用开源的 JFreeChart API(参见 参考资料)描绘(x,y)值。Swing 应用程序的完整源代码可以通过 javaxtools.compiler.examples.plotter 包的 可下载源代码 部分中获得。

这个应用程序的源代码生成需求非常普通。更为复杂的源代码模板工具可以更好地满足其他应用程序的需求,例如 Apache Velocity (参见 参考资料)。

安全风险和策略

如果应用程序允许用户随意输入 Java 源代码,那么会存在一些内在的安全风险。类似 SQL 注入(参见 参考资料),如果系统允许用户或其他代理提供原始的 Java 源代码来生成代码,那么恶意用户可能会利用这一点。例如,在本文的 Plotter 应用程序中,一个有效的 Java 表达式可能包含匿名的嵌套类,它可以访问系统资源、在受到拒绝服务攻击时产生大量线程或者执行其他行为。这些行为被称为 Java 注入。这种应用程序不应该部署在非信任用户可以随意访问的不可靠位置,例如作为 servlet 或 applet 的 Java EE 服务器。相反,javax.tools 的大多数客户机应该限制用户输入并将用户请求转换为安全的源代码。

使用这种包时可以采用的安全策略包括:

  • 使用定制的 SecurityManagerClassLoader 阻止加载匿名类或其他无法直接控制的类。

  • 使用源代码扫描程序或其他预处理程序,删除含有可疑代码构造的输入。例如,Plotter 可以使用 java.io.StreamTokenizer 并删除含有 {(左侧大括号)字符的输入,从而有效阻止了匿名或嵌套类的声明。

  • 使用 javax.tools API,JavaFileManager 可以删除任何预料之外的 CLASS 文件的写入。例如,当编译某个特定类时,对于要求保存预料之外的类文件的任何调用,JavaFileManager 将抛出一个 SecurityExeception 异常,并只允许生成用户无法猜测或欺骗的包名或类名。PlotternewFunction 方法使用的就是这种策略。

结束语

在本文中,我解释了 javax.tools 包的概念和重要接口,并展示了一个 façade,使用它编译保存在 String 或其他 CharSequence 中的 Java 源代码,然后使用这个库类开发可以描绘任意 f(x) 函数的样例应用程序。可以使用这种技术创建其他有用的应用程序:

  • 根据数据描述语言生成二进制文件阅读程序/写入程序。

  • 生成类似于 Java Architecture for XML Binding (JAXB) 或持久性框架的格式转换程序。

  • 通过执行源代码与 Java 语言的转换、Java 源代码编译和加载(类似于 JSP 技术),实现特定于域的语言解释器。

  • 实现规则引擎。

  • 您可以想像得到的任何内容。

下一次开发应用程序时,如果需要使用动态行为,请尝试 javax.tools 提供的多样性和灵活性。


下载

描述 名字 大小 下载方法 本文的样例代码
j-jcomp.zip 166KB HTTP

参考资料

学习
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • javax.tools:javax.tools 包 API 的 Javadoc 文档。

  • JSR 199: Java Compiler API:最早的 Java Specification Request,Java Community Process 根据该规范开发了 javax.tools 包。

  • Java design patterns 101”(David Gallardo,developerWorks,2002 年 1 月):该教程介绍了 Façade 和 Chain of Responsibility 模式,这些内容是在 Design Patterns: Elements of Reusable Object-Oriented Design (Erich Gamma et al.,Addison-Wesley,1994 年)中首次提出的。

  • 安全编程: 安全地调用组件”(David Wheeler,developerWorks,2004 年 12 月):本文介绍了 SQL 注入,这种安全漏洞允许用户指定插入到 SQL 语句中的原始文本,这些 SQL 语句随后会被提交到数据库。

  • 动态调用动态语言”(Tom McQueeney,developerWorks,2007 年 9月):这个包含两部分的系列文章描述了另一种使用 Java SE 6 轻松实现动态应用程序功能的方法。

  • 访问 developerWorks Java 技术专区,获得所需的资源提高 Java 技能。

  • 浏览 技术书店,查找有关本文所述主题和其他技术主题的图书。


获得产品和技术
  • Apache Velocity:该模板处理程序可以实现更灵活和更复杂的 Java 源代码生成。

  • Apache Commons JCI:这个现有 API 可以提供对 Java 编译器的访问。

  • Janino:Janino 提供了与 javax.tools 类似的功能,但是只与 Java 1.3 源代码兼容。

  • Javassist:Javassist 提供了动态的 Java 文件创建和加载功能,但是是通过字节码模型而不是 Java 源代码完成的。

  • JFreeChart:本文的样例应用程序使用了这个绘图 API。


讨论


关于作者

David Biesack

David Biesack 是 SAS Institute, Inc. 高级计算实验室的首席系统开发人员,主要研究高级分析学和分布式计算。在 SAS 的 19 年职业生涯中,David 利用 Java 语言进行设计和编码的时间长达 12 年。他参与制定了 JSR 201 规范,该规范向 Java 5 添加新的语法特性。















分享到:
评论

相关推荐

    [Java参考文档].JDK_API 1.6

    org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 org.omg.CORBA 提供 OMG CORBA API ...

    Java 1.6 API 中文 New

    org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 org.omg.CORBA 提供 OMG CORBA API ...

    JAVA动态编译

    本文主要介绍如何使用`JavaCompiler`接口进行Java源程序的动态编译,以及如何利用这一特性更好地理解和应用如JDK动态代理、CGLIB和Spring AOP等高级功能。 #### 一、JavaCompiler 接口 Java API 提供了`javax....

    Java深度历险

    这为创建灵活的应用程序提供了强大的工具。以下是一个简单的示例,展示如何使用这些API动态编译并执行Java代码: ```java import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import javax.tools....

    java 动态编译.java文件,动态运行类 _1.2

    Java提供了一个内置的`javax.tools.JavaCompiler`接口,它是Java工具接口(Java Tool API)的一部分,允许我们在程序中调用Javac编译器。要使用这个接口,首先需要引入`tools.jar`库,这个库通常位于Java安装目录的...

    学生的信息管理系统注释

    - `java.awt.*`:提供用于构建和管理应用程序用户界面的图形和图像工具。 - `java.awt.event.ActionEvent`、`ActionListener`:事件监听接口,处理用户操作。 - `java.io.File`:文件和目录路径名的抽象表示形式...

    java动态编译java源文件

    总的来说,Java动态编译和`Instrumentation`结合使用,能够实现强大的运行时代码修改功能,这在调试、测试、性能优化等领域都有着广泛的应用。但同时,这也需要对JVM内部机制有深入理解,以确保正确、安全地使用这些...

    内存中动态编译执行java代码

    内存中动态编译执行Java代码是一种高级编程技巧,它允许我们在程序运行时根据需要创建、编译和执行新的Java代码。这种技术在某些场景下非常有用,比如在元编程、插件系统、自定义脚本执行或者代码热更新中。在Java中...

    ejb 3.0 jar 包 很全 part2

    使用这个JAR,开发者可以在应用程序中远程调用部署在JBoss服务器上的EJB服务。 `jaxws-rt.jar`:这个文件包含了Java API for XML Web Services(JAX-WS)的运行时组件。JAX-WS是用于创建Web服务和消费Web服务的标准...

    java 动态编译.java文件,动态运行类

    首先,Java的`javac`命令行工具是用于编译Java源代码的标准方式,但在程序中实现动态编译则需要使用`javax.tools`包中的接口和类。这个包提供了一组API,允许我们直接在程序中进行编译操作,而无需调用外部的`javac`...

    移动编程j2me程序

    在移动编程领域,J2ME是一个重要的工具,因为它允许开发者创建跨平台的应用程序,覆盖广泛的用户群体。 **Eclipse IDE for J2ME** Eclipse是一款广泛使用的开源集成开发环境(IDE),支持多种编程语言,包括Java。...

    java动态编译指定java文件且将java文件生成jar

    在Java编程中,有时我们需要在运行时动态地编译源代码文件,并将其打包成可执行的JAR(Java Archive)文件。...这两个步骤结合起来,可以帮助我们在运行时构建和更新应用程序的代码部分,从而实现更加动态的功能。

    在java中利用动态编译实现eval

    值得注意的是,使用动态编译有一定的风险,因为它允许在运行时执行任意代码,可能会引入安全漏洞。因此,只有在必要时才应使用,并确保对输入进行严格的验证和限制。 此外,Java 9引入了JShell(也称为REPL,Read-...

    Java6动态编译案例

    总结来说,Java6的动态编译能力极大地增强了Java应用程序的灵活性和适应性,使得开发者可以在运行时根据需要编译和加载新的代码,这对于实现某些高级功能,如元编程、自我优化的系统以及动态代码生成等,都具有重要...

    Web环境下Java表达式的动态编译与计算.pdf

    动态编译的实现分为四步:首先,调用javax.tools.ToolProvider类的getSystemJavaCompiler方法获得编译器对象;然后,调用编译器对象的getTask方法创建编译作业对象,并指定一个Java文件管理器,用于获取用于保存编译...

    java 动态编译打包 动态编译可以用于实现动态代码生成、动态加载、插件化等功能

    Java 动态编译打包是Java开发中的一个重要技术,它允许程序在运行时生成和编译源代码,然后即时加载到应用程序中。这种技术在许多场景下都非常有用,例如实现动态代码生成、动态加载和插件化系统。下面将详细讨论...

    Java语言-动态编译代码并热加载类

    在Java编程中,动态编译代码并热加载类是一项重要的技术,它允许程序在运行时修改或添加新的类,而无需重启应用。这种能力对于快速迭代开发、调试和性能优化非常有用。本主题将深入探讨Java中的动态编译与热加载机制...

    EJB3.0开发Message Driven Bean

    Enterprise JavaBeans (EJB) 是一种基于Java的应用程序编程接口(API),用于开发分布式企业级应用。EJB3.0作为Java EE5规范的一部分,引入了许多简化开发的新特性。其中Message-Driven Bean (MDB) 是一种特殊类型的...

    Java 动态编译源码并调用

    Java 动态编译源码并调用是Java开发中的一种高级技巧,它允许程序在运行时根据需要编译和执行新的代码。这种能力在某些场景下非常有用,例如插件系统、元编程或者在运行时自动生成和执行特定逻辑。下面我们将详细...

    java swing 做的QQ聊天程序

    - Swing 应用程序通常包含一个主类,该类继承自 javax.swing.JFrame 或 javax.swing.JApplet,作为应用程序的主窗口。 2. **网络通信**: - 使用Java的Socket编程,客户端与服务器之间通过TCP/IP协议进行通信。...

Global site tag (gtag.js) - Google Analytics