- 浏览: 125591 次
- 性别:
- 来自: 山东
最新评论
一般情况下对java源文件的编译均是在代码完成后使用javac编译的,不管是使用IDE还是直接使用命令行。这里要说的情况是比较特别的,就是在代码内动态的编译一些代码。比如你想通过在某个目录下通过放置一些源代码的方式来实现对程序功能的动态扩展,那么你的程序就需要具有一种对源代码的编译、加载、运行的能力,可能就需要本文介绍的3种方法。
可以和JAVA的类加载器结合使用,动态编译、动态加载。
方法1:通过调用本机的javac命令来编译
在java程序中调用javac命令可以通过调用Runtime类的exec或是ProcessBuilder类的start方法来完成,这两个类的功能 基本相同,用法也比较相似。如果是JDK1.5之前的版本请使用Runtime类完成相同的功能。
利用指定的操作系统程序和参数构造一个进程生成器。这是一个有用的构造方法,它将进程生成器的命令设置为与 command 数组包含相同字符串的字符串列表,且顺序相同。不必检查 command 是否为一个有效的操作系统命令。
利用修改过的工作目录和环境启动进程的例子:
pb.environment()返回此进程生成器环境的字符串映射视图。 无论进程生成器何时创建,都需要将环境初始化为一份当前进程环境的副本(请参阅 System.getenv())。由此对象的 start() 方法启动的后续子进程将使用这一映射作为它们的环境。
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。
方法2:使用Sun的tools.jar包的com.sun.tools.javac.Main类完成对代码的编译
其构造方法为public Main(OutputStream outputstream, String s)。使用tools.jar的com.sun.tools.javac.Main编译时,主要是调用该类的compile(String [] args)/compile(String [] args, PrintWirter pw)。
方法3:使用javax.tools包
从上面可以看到方法2的缺点就是tools.jar需要我们自行导入。而在Java SE6中为我们提供了标准的包来操作Java编译器,这就是javax.tools包。使用这个包,我们可以不用将jar文件路径添加到classpath中了。 使用这个类的方法和上面的类很相似,我只需要将
替换成
//将编译参数通过数组传递到编译方法中,该函数的方法和javac的参数完成一致
可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。
JavaCompiler中最核心的方法是run。通过这个方法可以编译java源程序。这个方法有3个固定参数和1个可变参数(可变参数是从 Jave SE5开始提供的一个新的参数类型,用type… args表示)。前3个参数分别用来为java编译器提供参数、得到Java编译器的输出信息以及接收编译器的错误信息,后面的可变参数可以传入一个或多个Java源程序文件。如果run编译成功,返回0。
可以和JAVA的类加载器结合使用,动态编译、动态加载。
方法1:通过调用本机的javac命令来编译
javac –encoding char_set –classpath/-cp classpath –d dir src
在java程序中调用javac命令可以通过调用Runtime类的exec或是ProcessBuilder类的start方法来完成,这两个类的功能 基本相同,用法也比较相似。如果是JDK1.5之前的版本请使用Runtime类完成相同的功能。
public ProcessBuilder(String... command)
利用指定的操作系统程序和参数构造一个进程生成器。这是一个有用的构造方法,它将进程生成器的命令设置为与 command 数组包含相同字符串的字符串列表,且顺序相同。不必检查 command 是否为一个有效的操作系统命令。
Process p = new ProcessBuilder("command", "arg1" [, arg2] [,arg3] [,……]).start();
Process proc = new ProcessBuilder("javac", "-d", "d:\\test\\bin", "d:\\test\\src\\Test.java").start();
利用修改过的工作目录和环境启动进程的例子:
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2"); Map<String, String> env = pb.environment(); env.put("VAR1", "myValue"); env.remove("OTHERVAR"); env.put("VAR2", env.get("VAR1") + "suffix"); pb.directory(new File("myDir")); Process p = pb.start();
pb.environment()返回此进程生成器环境的字符串映射视图。 无论进程生成器何时创建,都需要将环境初始化为一份当前进程环境的副本(请参阅 System.getenv())。由此对象的 start() 方法启动的后续子进程将使用这一映射作为它们的环境。
public class Runtime extends Object
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。
runtime.exec("javac -d d:\\test\\dir d:\\test\\src\\Test.java");
方法2:使用Sun的tools.jar包的com.sun.tools.javac.Main类完成对代码的编译
其构造方法为public Main(OutputStream outputstream, String s)。使用tools.jar的com.sun.tools.javac.Main编译时,主要是调用该类的compile(String [] args)/compile(String [] args, PrintWirter pw)。
int returnValue = Main.compile(new String[] {"-classpath", compilepath, "-d", dir, src});
PrintWriter pw = new PrintWriter("d:\\test\\src\\test.txt"); int returnValue = Main.compile(new String[] {"-classpath", compilepath, "-d", dir, src}, pw); //暂时没有弄明白pw在运行中的作用
public class DynamicCompileTest { public static void main(String[] args) { try { String className = "RunTime"; String classDir = System.getProperty("user.dir"); File file = new File(classDir, className + ".java"); PrintWriter out = new PrintWriter(new FileOutputStream(file)); // 代码 StringBuffer sbf = new StringBuffer(128); sbf.append("public class "); sbf.append(className); sbf.append("{"); sbf.append("public void hello () {"); sbf.append("System.out.println(\"DynamicCompile Success.\");"); sbf.append("}"); sbf.append("}"); String code = sbf.toString(); out.println(code); out.flush(); out.close(); // 编译 com.sun.tools.javac.Main.compile(new String[] { "-d", classDir, file.getName() });// JAVA_HOME/jdk/lib/tools.jar URL url = new URL("file:/" + classDir + File.separator); // 动态加载/执行 URLClassLoader loader = new URLClassLoader(new URL[] { url }); Class<?> clazz = loader.loadClass(className); Object obj = clazz.newInstance(); Method method = clazz.getMethod("hello"); method.invoke(obj); } catch (Exception e) { e.printStackTrace(); } } }
方法3:使用javax.tools包
从上面可以看到方法2的缺点就是tools.jar需要我们自行导入。而在Java SE6中为我们提供了标准的包来操作Java编译器,这就是javax.tools包。使用这个包,我们可以不用将jar文件路径添加到classpath中了。 使用这个类的方法和上面的类很相似,我只需要将
Main.compile(new String[]{"-encoding", "UTF-8","-d", binDir, filePath});
替换成
//将编译参数通过数组传递到编译方法中,该函数的方法和javac的参数完成一致
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); compiler.run(null, null, null, "-encoding", "UTF-8","-d", binDir, filePath);
可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaCompiler中最核心的方法是run。通过这个方法可以编译java源程序。这个方法有3个固定参数和1个可变参数(可变参数是从 Jave SE5开始提供的一个新的参数类型,用type… args表示)。前3个参数分别用来为java编译器提供参数、得到Java编译器的输出信息以及接收编译器的错误信息,后面的可变参数可以传入一个或多个Java源程序文件。如果run编译成功,返回0。
int run(InputStream in, OutputStream out, OutputStream err, String... arguments)
int result = compiler.run(null, null, null, "-encoding", "UTF-8", "-cp", "C:/Java/jdk1.6.0_18/lib/tools.jar", "-d", binDir, filePath);
<<To Be Continued>>
发表评论
-
闷葫芦的世界
2016-01-09 22:57 374工作几年,零零散散也整理了不少东西,但都是东一榔头西一棒槌的, ... -
JavaMail(一)
2011-04-26 18:04 1237浅谈邮件传输协议 SMTP(Simple Ma ... -
Tomcat配置SSL的双向认证
2011-04-26 16:58 2428证书保存在服务器端,用户通过浏览器访问时,需要 ... -
Tomcat配置SSL的客户端认证
2011-04-26 16:41 2447证书保存在服务器端,用户通过浏览器访问时,需要 ... -
Java实现国际化
2011-04-20 15:15 13181.根据不同语言环境使用不同文件 ... -
Java动态编译(二)
2011-04-19 17:16 2279在上一篇(Jav ... -
Java抽象类和接口
2011-04-18 15:34 2075一个Java接口(Interface)是一些方 ... -
Java线程(三)
2011-04-15 11:51 1218浅谈synchronized应何时使用 ... -
Java线程(二)
2011-04-15 10:23 985浅谈synchronized应用于类方法和类字面量之上 ... -
Java线程(一)
2011-04-14 11:29 966线程同步:synchronized方法和syn ... -
ClassLoader
2011-04-12 16:58 1179当运行Java程序时,首先运行JVM(java虚拟 ... -
NIO第二部分复用和编码
2011-04-08 14:46 828public abstract class Sel ... -
NIO第一部分缓冲区和通道
2011-04-08 14:40 1409系统运行的性 ... -
CLASSPATH和PATH
2011-04-06 13:45 2033J2SDK(Software Devel ...
相关推荐
JavaCompiler --JDK6 API 的简介(java动态编译) JavaCompiler 是 Java 中的一个编译器...JavaCompiler 是 Java 中的一个重要的编译器接口,提供了标准的方式来操作 Java 编译器,并且广泛应用于 Java 动态编译中。
在Java编程中,有时我们需要在运行时动态地编译源代码文件,并将其打包成可执行的JAR(Java Archive)文件。这样的需求通常出现在我们希望根据用户输入或特定条件生成并执行新的代码逻辑时。本教程将深入讲解如何...
Java动态编译指的是在程序运行时将Java源代码编译为字节码并加载到Java虚拟机(JVM)中的过程。这种技术在许多场景下非常有用,例如在开发环境中进行快速迭代、AOP(面向切面编程)或运行时代码生成等。Java的`javax...
添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6.传入JavaFileObject的java文件,是个集合,创建JavaSourceObject实现这个接口,Kind.SOURCE.extension = '.java' * 7.创建任务并...
在Java编程中,动态编译和运行类是一项重要的能力,特别是在需要实时更新代码或实现热部署的场景下。本文将深入探讨如何利用Java的API来动态编译.java源文件,并执行编译后的类。 首先,Java的`javac`命令行工具是...
这篇博客“Java类动态加载(一)——java源文件动态编译为class文件”可能主要探讨了如何在运行时将Java源代码(.java)编译成对应的字节码文件(.class),并将其加载到Java虚拟机(JVM)中。以下是对这个主题的详细解析...
JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA...
SpringBoot 应用动态编译 Java 源码并注入 Spring 容器,实现动态修改接口和抽象类的实现。注意,项目以 Jar 包形式启动时要在命令行引入 tools.jar 的包,IDEA下可直接调试。 基于接口、抽象类实现不停机动态调整...
在Java编程中,动态编译和运行类是一项重要的技术,特别是在需要实时更新代码或实现热部署的场景下。本文将详细讲解如何在Java中实现动态编译.java源代码文件并执行编译后的类。 首先,我们需要理解Java的编译过程...
1. **Java编译API:Javacompiler接口** Java提供了一个内置的`javax.tools.JavaCompiler`接口,它是Java工具接口(Java Tool API)的一部分,允许我们在程序中调用Javac编译器。要使用这个接口,首先需要引入`tools...
Java动态编译是一种技术,允许程序在运行时将源代码转换为字节码并加载到JVM(Java虚拟机)中。这种能力使得Java应用程序能够根据需要编译和执行新的代码,增强了软件的灵活性和可扩展性。在给定的场景中,用户通过...
Java 动态编译源码并调用是Java开发中的一种高级技巧,它允许程序在运行时根据需要编译和执行新的代码。这种能力在某些场景下非常有用,例如插件系统、元编程或者在运行时自动生成和执行特定逻辑。下面我们将详细...
Java内存动态编译执行是Java程序运行时的一个关键特性,它涉及到JVM(Java虚拟机)的即时编译器(JIT,Just-In-Time Compiler)和元空间(Metaspace)等核心概念。在Java的世界里,代码首先会被解释器逐行解释执行,...
Java反编译工具是程序员在开发和调试过程中经常会用到的一种实用软件,它能够将已编译的Java字节码(.class文件)转换回源代码格式,这对于查看和理解第三方库或者研究已有的二进制代码非常有帮助。本绿色版的Java反...
JAD是另一个知名的Java反编译工具,它提供命令行接口,适合于自动化脚本或者集成到其他工具链中。FernFlower则是一个开源的反编译器,它的反编译效果通常较好,但可能需要更多的配置和调试。 需要注意的是,反编译...
利用Java的动态编译、动态加载结合EasyRules实现业务规则的动态性的项目源码,具体详情请查看相关博客https://blog.csdn.net/qq_31142553/article/details/85013989
然而,出于调试、学习或者逆向工程的目的,有时我们需要查看一个已编译的Java类文件的源代码,这时就需要用到反编译工具。标题中的“jd_gui.exe”就是一种常用的Java反编译工具,名为JadGUI。 JadGUI是Jad的图形...
这款名为“咖啡图形的java反编译工具”很可能是一款界面友好的图形化工具,专为简化这个过程而设计。 Java字节码是一种中间语言,由Java编译器生成,可以在任何支持Java虚拟机(JVM)的平台上运行。然而,由于字节...