00-JAVA基础-动态编译

动态编译

JAVA 6 引入了动态编译机制。Java 动态编译是指在运行时将Java源代码编译成可执行的字节码。这通常使用Java的内置编译器API javax.tools.JavaCompiler 来实现。

动态编译的应用场景

  • 可以做一个浏览器编写java代码,上传服务器编译和运行的在线测评系统
  • 服务器动态加载某些类文件进行编译

动态编译的两种实现方式

  • JAVA6之前,可以通过Runtime调用javac,启动新的进程去操作

    Runtime run = Runtime.getRuntime();
    Process process = run.exec("javac D:/myjava/demo/HelloWorld.java");
    
  • JAVA6之后,可以使用JavaCompiler实现

      public static in compileFile(String sourceFile){JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();int result = compiler.run(null,null,null,sourceFile);System.out.println(result == 0 ? "编译通过" : "编译失败")return result;}
    

compiler.run(null,null,null,sourceFile)参数说明:

第一个参数:为java编译器提供参数
第二个参数:得到Java编译器的输出信息
第三个参数:接受编译器的错误信息
第四个参数:可变参数(是一个String[]数组)能传入一个或多个Java源文件
返回值:0 表示编译成 ,非0 表示编译失败

使用runtime.exec方法编译

package demo2;import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;/*** 使用Runtime编译,通过反射调用main方法** @author Anna.* @date 2024/4/4 11:13*/
public class DyanmaicDemo {public static void main(String[] args) throws Exception {String path = DyanmaicDemo.class.getResource("").getPath();String javaName = "Hello";// 创建文件File tempFile = createFile(path, javaName);// 使用Runtime 编译compilation(tempFile);// 反射执行文件extracted(path, javaName);}/*** 创建文件** @param path* @param javaName* @return java.io.File* @author Anna.* @date 2024/4/4 13:05*/private static File createFile(String path, String javaName) throws IOException {// 创建编译内容StringBuffer sb = new StringBuffer();sb.append("public class ").append(javaName).append("{").append("public static void main(String[] args){").append("System.out.println(\"hello world !!!\");").append("}").append("}");// 写入临时文件File tempFile = new File(path + javaName + ".java");FileWriter fileWriter = new FileWriter(tempFile);fileWriter.write(sb.toString());fileWriter.close();return tempFile;}/*** 编译** @param tempFile* @return void* @author Anna.* @date 2024/4/4 13:05*/private static void compilation(File tempFile) throws IOException, InterruptedException {String replace = tempFile.getAbsolutePath().replace(tempFile.getName(), "");replace = replace.substring(0, replace.length() - 1);String str = "javac " + tempFile.getAbsolutePath();Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(str);// 读取命令的标准输出BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 读取命令的错误输出BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));while ((line = errorReader.readLine()) != null) {System.err.println(line);}// 等待进程结束并获取退出值int exitValue = process.waitFor();if (exitValue == 0) {System.out.println("Compilation is successful");} else {System.out.println("Compilation Failed");}}/*** 反射执行main方法** @param path* @param javaName* @return void* @author Anna.* @date 2024/4/4 13:05*/private static void extracted(String path, String javaName) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:/" + path)});Class<?> clazz = urlClassLoader.loadClass(javaName);Method mainMethod = clazz.getMethod("main", String[].class);// 注意:由于可变参数是JDK5之后才有的,下面代码如果new String[]{"1","2"}强制在转换才Object,则会被编译成 mainMethod.invoke(null,"1","2"),从而导致找不到方法。// 因此,如果传参则徐亚加上(Object),避免这个问题mainMethod.invoke(null, (Object) new String[]{"1", "2"});}}

执行结果

在这里插入图片描述

使用JavaCompiler实现

package demo1;import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;/*** 使用JavaCompiler编译,通过反射调用main方法** @author Anna.* @date 2024/4/4 10:55*/
public class DyanmicDemo1 {public static void main(String[] args) throws Exception {// 创建编译内容String javaName = "Hello";// 获取JavaFileObjectJavaFileObject source = getJavaFileObject(javaName);// 编译compiler(source);// 执行extracted(javaName);}/*** 获取JavaFileObject** @param javaName* @return javax.tools.JavaFileObject* @author Anna.* @date 2024/4/4 13:56*/private static JavaFileObject getJavaFileObject(String javaName) {StringBuffer sb = new StringBuffer();sb.append("public class ").append(javaName).append("{").append("public static void main(String[] args){").append("System.out.println(\"hello world !!!\");").append("}").append("}");// 创建一个Java源代码文件 string:///是一个特殊的URI协议,用于表示源代码内容直接来自一个字符串,而不是来自文件系统中的一个文件。 好处是,你可以完全在内存中处理源代码,无需涉及文件系统的I/O操作。JavaFileObject source = new SimpleJavaFileObject(URI.create("string:///" + javaName + ".java"), JavaFileObject.Kind.SOURCE) {@Overridepublic CharSequence getCharContent(boolean ignoreEncodingErrors) {return sb.toString();}};return source;}/*** 编译** @param source* @return void* @author Anna.* @date 2024/4/4 13:49*/private static void compiler(JavaFileObject source) {// 获取系统Java编译器JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();// 创建诊断收集器DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();// 创建编译任务StandardJavaFileManager fileManager = systemJavaCompiler.getStandardFileManager(diagnostics, null, null);// 设置输出目录Iterable<? extends File> locations = fileManager.getLocation(StandardLocation.CLASS_OUTPUT);try {fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(new File(DyanmicDemo1.class.getClassLoader().getResource("").getPath())));} catch (IOException e) {e.printStackTrace();return;}Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(source);JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);// 执行编译任务boolean success = task.call();// 关闭文件管理器try {fileManager.close();} catch (IOException e) {e.printStackTrace();}// 处理编译诊断信息for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {System.out.println(diagnostic);System.out.println(diagnostic.getKind() + ": " + diagnostic.getMessage(null));}System.out.println(success ? "编译通过" : "编译失败");}/*** 反射执行** @param javaName* @return void* @author Anna.* @date 2024/4/4 13:50*/private static void extracted(String javaName) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:/" + DyanmicDemo1.class.getClassLoader().getResource("").getPath())});Class<?> clazz = urlClassLoader.loadClass(javaName);Method mainMethod = clazz.getMethod("main", String[].class);// 注意:由于可变参数是JDK5之后才有的,下面代码如果new String[]{"1","2"}强制在转换才Object,则会被编译成 mainMethod.invoke(null,"1","2"),从而导致找不到方法。// 因此,如果传参则徐亚加上(Object),避免这个问题mainMethod.invoke(null, (Object) new String[]{"1", "2"});}}

执行结果

在这里插入图片描述

注意:

Runtime不仅仅是可以用于执行javac,当然可以用来执行其他命令,这里就不进一步说明了

CommandUtil调用系统命令工具类

import org.apache.commons.exec.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;/*** 调用系统命令工具类** @author Anna.* @date 2021/9/8 16:05*/
public class CommandUtil {private static Logger logger = LoggerFactory.getLogger(CommandUtil.class);private static final String DEFAULT_CHARSET = "UTF-8";private static final Long TIMEOUT = 10000L;/*** 执行指定命令** @param command 命令* @return 命令执行完成返回结果* @throws RuntimeException 失败时抛出异常,由调用者捕获处理*/public synchronized static String exeCommand(String command) throws RuntimeException {try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {int exitCode = exeCommand(command, out);if (exitCode == 0) {logger.info("命令运行成功:" + System.currentTimeMillis());} else {logger.info("命令运行失败:" + System.currentTimeMillis());}return out.toString(DEFAULT_CHARSET);} catch (Exception e) {logger.info(e.getMessage());throw new RuntimeException(e.getMessage());}}/*** 执行指定命令,输出结果到指定输出流中** @param command 命令* @param out     执行结果输出流* @return 执行结果状态码:执行成功返回0* @throws ExecuteException 失败时抛出异常,由调用者捕获处理* @throws IOException      失败时抛出异常,由调用者捕获处理*/public synchronized static int exeCommand(String command, OutputStream out) throws ExecuteException, IOException {CommandLine commandLine = CommandLine.parse(command);PumpStreamHandler pumpStreamHandler = null;if (null == out) {pumpStreamHandler = new PumpStreamHandler();} else {pumpStreamHandler = new PumpStreamHandler(out);}// 设置超时时间为10秒ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT);DefaultExecutor executor = new DefaultExecutor();executor.setStreamHandler(pumpStreamHandler);executor.setWatchdog(watchdog);return executor.execute(commandLine);}public static void main(String[] args) {String out = null;try {
//            out = CommandUtil.exeCommand("ipconfig");out = CommandUtil.exeCommand("D:\\SoftWare\\ffmpeg\\bin\\ffmpeg.exe -y  -i D:/test/1631090617181_191979483992900.mp3  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 D:/test/PCM1631090617181_191979483992900.mp3.pcm");} catch (Exception e) {e.printStackTrace();}System.out.println(out);//CommandUtil.executeCommand("kill -9 3104");}}

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593998.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaSE】反射

Java代码的生命周期 Java代码在计算机中经历的阶段&#xff1a;Source源代码阶段、Class类对象阶段、RunTime运行时阶段。 Source源代码阶段: 这个阶段是由程序员编写生成源代码,再由Javac编译器生成class文件。 Class类对象阶段&#xff1a;由类加载器将class文件加载到JVM内…

动规训练3

一、按摩师 1、题目解析 简而言之就是&#xff0c;找到一个按摩师的预约总是长的最长方案&#xff0c;还有一个限制条件&#xff0c;选取的预约两两不相邻。 2、算法原理 a状态表示方程 小技巧&#xff1a;经验题目要求 dp[i]表示以这个节点为结尾&#xff0c;最长的预约时…

Calico IPIP和BGP TOR的数据包走向

IPIP Mesh全网互联 文字描述 APOD eth0 10.7.75.132 -----> APOD 网关 -----> A宿主机 cali76174826315网卡 -----> Atunl0 10.7.75.128 封装 ----> Aeth0 10.120.181.20 -----> 通过网关 10.120.181.254 -----> 下一跳 BNODE eth0 10.120.179.8 解封装 --…

哈佛大学商业评论 --- 第四篇:一家公司的AR经验

AR将全面融入公司发展战略&#xff01; AR将成为人类和机器之间的新接口&#xff01; AR将成为人类的关键技术之一&#xff01; 请将此文转发给您的老板&#xff01; --- 专题作者&#xff1a;Michael E.Porter和James E.Heppelmann 虽然物理世界是三维的&#xff0c;但大多…

LeetCode每日一题之专题一:双指针 ——快乐数

快乐数OJ链接&#xff1a;202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 题目分析: 为了房便叙述&#xff0c;将「对于⼀个正整数&#xff0c;每⼀次将该数替换为它每个位置上的数字的平方和」这⼀个 操作记为 x 操作&#xff1b; 题目告诉我们&#…

什么是原生IP?原生IP的作用是什么?

原生IP&#xff08;Native IP&#xff09;是指直接从互联网服务提供商&#xff08;ISP&#xff09;获得的IP地址&#xff0c;而非通过代理服务器、VPN或其他中间层方式获取。这种IP地址直接与用户的设备或网络关联&#xff0c;无需经过任何中间服务器或代理的转发或隐藏&#x…

如何才能实现基坑自动化监测?

基坑自动化监测是一个系统性的过程&#xff0c;它涉及对基坑整体情况的全面了解和分析&#xff0c;确定监测指标&#xff0c;选择合适的监测传感器并进行安装和调试&#xff0c;配置相应的数据采集、传输和管理软件系统&#xff0c;以及进行系统的调试、定期维护和数据分析。以…

uni-app调用苹果登录,并获取用户信息

效果 模块配置 dev中的配置 需要开启登录的权限&#xff0c;然后重新下载配置文件&#xff0c;发布打包基座&#xff0c;再运行程序 代码 <button click"appleLogin">苹果登录</button>function appleLogin() {uni.login({provider: apple,success: …

免版权素材库:在营销和宣传中的重要性与应用

title: 免版权素材库&#xff1a;在营销和宣传中的重要性与应用 date: 2024/4/5 18:21:43 updated: 2024/4/5 18:21:43 tags: 免版权素材库营销宣传高质量素材节省成本避免侵权创意启发数字营销 免版权素材库在宣传和营销中的重要性不言而喻。在当今数字化时代&#xff0c;图片…

html5如何在使用原生开发的情况下实现组件化

我们知道如何在vue/react中使用组件化开发&#xff0c;那么如果只是一个简单的界面&#xff0c;一个HTML就搞定的事情&#xff0c;你还会去新建一个vue/react项目吗&#xff1f; 在使用原生HTML开发时&#xff0c;我们也会遇到一些常见的功能、模块&#xff0c;那么如何在原生…

Flask-RESTful 分析

Flask-RESTful 是一个 Flask 扩展&#xff0c;它为构建 RESTful API 提供了方便的工具和资源。它简化了创建 RESTful 服务的过程&#xff0c;允许开发者专注于业务逻辑而不是 HTTP 协议的细节。 资源&#xff08;Resources&#xff09;&#xff1a; Resource 类&#xff1a;是…

WIFI|软体 茶凳浅谈 高通WIN QSDK - IPQ6000 与 88Q2112 的相遇

Qualcomm IPQ 系列的Ethernet IC 搭配的有 QCA8075, QCA8081 … 等等Qualcomm自家出产的芯片。QSDK中内建可以支持的3rd party芯片&#xff0c;却寥寥可数。日前&#xff0c;客户使用车载以太网 - 88Q2112 - Marvell与IPQ6000做搭配。将之记录下来&#xff0c;以供参考。 方…