范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Java源代码动态编译类加载和代码执行(Java8)

  #头条创作挑战赛#
  Java 的一个重要特性是动态的类加载机制。通过在运行时动态地加载类,Java 程序可以实现很多强大的功能。下面通过一个具体的实例来说明 Java 程序中,如何动态地编译 Java 源代码、加载类和执行类中的代码。这里的代码示例适用的版本是 Java 8。
  示例所实现的功能很简单,就是对表达式求值。输入的是类似 1 + 1 或 3 * (2 + 3) 这样的表达式,返回的是表达式的值。示例的做法是动态创建一个 Java 源文件,编译该文件生成 class 文件,加载 class 文件之后再执行。比如,需要求值的表达式是 1 + 1,那么所生成的 Java 源文件如下所示,其中 1 + 1 的部分是动态的。public class Calculator {     public static Object calculate() {         return 1 + 1;     } }
  我们只需要编译该源文件,加载编译之后的 class 文件,再通过反射 API 来调用其中的 calculate 方法就可以得到表达式求值的结果。编译
  第一步是动态生成 Java 源代码并编译。生成 Java 源代码比较简单,直接用字符串连接就可以了。当然了,在生成逻辑比较复杂时,推荐的做法是使用字符串模板引擎,如 Handlebars。在下面的代码中,getJavaSource 方法生成 Java 源代码,compile 方法进行编译。
  在进行编译的时候,使用的是 JDK 标准的 JavaCompiler 接口。从源代码字符串中创建了一个 JavaFileObject 对象作为编译时的源代码单元。编译时的选项 -d 指定了编译结果的输出路径,这里是一个临时文件夹。compile 方法的返回值是一个 Pair 对象,包含了 class 文件的路径,以及随机生成的 Java 包的名称。public class DynamicCompilation {    private static final String CLASS_NAME = "Calculator";    public static Pair compile(String expr) throws IOException {     String packageName = "z" + UUID.randomUUID().toString().replace("-", "");     Path outputPath = Files.createTempDirectory("expr");     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();     StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,         null, null);     compiler.getTask(null, fileManager, null, ImmutableList.of(                 "-d", outputPath.toAbsolutePath().toString()             ), null,             Collections.singletonList(                 new StringContentJavaFileObject(CLASS_NAME,                     getJavaSource(packageName, expr))))         .call();     return Pair.of(outputPath, packageName + "." + CLASS_NAME);   }    private static String getJavaSource(String packageName, String expr) {     return "package " + packageName + "; "         + "public class " + CLASS_NAME         + " { public static Object calculate() {  "         + "return " + expr + "; }" +         "}";   } }
  上面的代码用到了一个帮助类 StringContentJavaFileObject,表示从字符串创建的 JavaFileObject 对象。public class StringContentJavaFileObject extends SimpleJavaFileObject {    private final String content;    public StringContentJavaFileObject(String name, String content) {     super(URI.create("string:///" + name + Kind.SOURCE.extension),         Kind.SOURCE);     this.content = content;   }    @Override   public CharSequence getCharContent(boolean ignoreEncodingErrors) {     return content;   } }
  加载
  编译完成之后的第二步是动态加载类。这一步并没有实现自定义的类加载器,而且使用内置的系统类加载器。系统类加载器通过 ClassLoader.getSystemClassLoader() 方法来获取。系统类加载器在 classpath 上查找类。这里用了一个比较 hack 的技巧来动态修改系统类加载器的 classpath。
  在下面的代码中,ClasspathUpdater 的 addPath 方法可以把一个 Path 对象表示的路径,添加到系统类加载器的查找路径中。这是因为系统类加载器自身是 URLClassLoader 类型的加载器,其中的 addURL 方法可以添加新的查找路径。只不过 addURL 方法是 protected,这里通过反射 API 来进行调用。public class ClasspathUpdater {    public static void addPath(Path path) {     URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();     try {       Method method = URLClassLoader.class.getDeclaredMethod("addURL",           URL.class);       method.setAccessible(true);       method.invoke(classLoader, path.toUri().toURL());     } catch (Exception e) {       throw new RuntimeException(e);     }   }  }
  上面介绍的 ClasspathUpdater 类中的使用技巧,只对 Java 8 生效。在 Java 9 引入模块系统时,对系统类加载器进行了修改。系统类加载器被替换成了应用类加载器。应用类加载器不再是 URLClassLoader 类型了,就不能使用这个技巧了。执行
  最后一步就是执行动态加载的 Java 类。这一步比较简单,只需要用 Class.forName 方法来查找 Java 类,再找到对应的 Method 对象,直接调用即可。下面的代码给出了示例。public class Invoker {    public static Object invoke(String className) {     try {       Method method = Class.forName(className).getDeclaredMethod("calculate");       return method.invoke(null);     } catch (Exception e) {       throw new RuntimeException(e);     }   } }完整的执行过程
  最后把整个流程串起来。在下面的代码中,需要求值的表达式是 (1 + 1) * 3 / 5.0。首先调用 DynamicCompilation.compile 方法进行动态编译,得到 class 文件的路径和完整的类名。class 文件的路径通过 ClasspathUpdater.addPath 方法添加到 classpath 中。完整的类名则传递给 Invoker.invoke 方法来执行。最后输出的结果是表达式的值。public class Main {    public static void main(String[] args) throws IOException {     Pair result = DynamicCompilation.compile("(1 + 1) * 3 / 5.0");     ClasspathUpdater.addPath(result.getLeft());     System.out.println(Invoker.invoke(result.getRight()));   } }

伊朗卡塔尔谁是中国男足历史上最大的苦主?我对他们的所见所闻2022年卡塔尔世界杯揭开战幕,亚洲杯冠军卡塔尔和伊朗先后亮相,表现令人失望。好多网友说如果换成中国队。呜呼,我们还是略过这个梗儿吧。说起来,其实这两个国家其实都是中国足球队历史上中国裁判亮相世界杯得信任继续新任务继北京时间11月22日在世界杯B组美国队与威尔士队比赛中作为第四官员亮相之后,中国裁判马宁领到了新任务在北京时间11月24日零时E组首轮西班牙队与哥斯达黎加队比赛中继续担任第四官员中国斯诺克5胜1负!新星爆冷塞尔比,替补大胜,冠亚军会师正赛?今晨,斯诺克德国大师赛结束第2日较量,中国军团表现出色,取得5胜1负的彪炳战绩。赵心童田鹏飞携手进正赛,新星彭奕淞爆冷绝杀塞尔比,顶替梁文博出战的赵剑波51大胜晋级,颜丙涛今晚迎来中国男足参加世界杯最佳解决方案2022卡塔尔世界杯,不出意外的我们男足又一次虽败犹荣的打道回府,没有资格参加。为解决这一千古难题,本人想出一方案,百分百的保证以后历届世界杯都有我们男足的身影。那就是!男足以世界为闯过2000度高温,中国与美国,在测试同款防护罩从外太空返回地球,所有飞船都面临着一个问题,那就是重力加速度带来的影响。飞船进入地球的技巧二次进入通过重力加速度,飞船表面温度能够升至2000摄氏度,非常考验飞船的材质。为了闯过2风味人间,一份不可错过的中国旅行美食地图在旅行中,美景跟美食是分不开的,特别是对于一个匆匆过客,如果想要更好地去了解当地的风土人情,大概食物是最直白的传递工具。用蔡澜的话来说就是认识一个地方的文化,就要去菜市场咯。相比老武则天以女流之身在男尊时代走向权力巅峰武则天于唐武德七年生于长安,家境比较殷实,但是家族并非显赫,因而武则天幼时遭受了不少贵族小姐的冷嘲热讽。也是这个原因,让武则天对权势产生了狂热追求,养成了倔强不服输和报复不择手段的数字经济概念10大龙头股数字经济是一种新型经济形态,主要涉及大数据云计算区块链5G通信物联网人工智能等技术。作为十四五规划的重要组成部分,我们来了解一下前10大龙头股。1中兴通讯简介通信行业最大龙头,一方利率天花板下压增额终身寿险成香饽饽关注理财投资的一些朋友可能已经收到消息3。5利率的增额终身寿险最近成为了香饽饽!有很多人都都在抢购!怎么回事?什么是增额终身寿险?为什么大家都在抢购增额终身寿险呢?接下来,小逸就为欧洲只租不卖的蔚来,今天叛变了出品丨虎嗅汽车组作者丨周到图片丨视觉中国蔚来,又一次屈服于用户需求。当地时间2022年11月21日,蔚来在德国瑞典丹麦荷兰四个国家开启了买断模式。此前,蔚来在欧洲上述四国仅提供订阅关注巴菲特再次减持比亚迪,累计套现超百亿港元文懂车帝原创邢秋鸿懂车帝原创行业11月22日,港交所官网显示,巴菲特旗下公司伯克希尔于11月17日卖出了322。5万股比亚迪H股,对比亚迪H股持股比例从16。28降至15。99。本
真正的人生从你醒来的那刻开始今天对这句话非常共振同频!keepcalmandbepatient!这也是接下来或者是很长的一段时间自己的人生课题!保持冷静耐心!人有两次生命,一次是出生,一次是觉醒。第一次是为别你要写屈原,但是你不能只写屈原你要写屈原,但是你不能只写屈原。你要写他年少,要写那春兰秋菊,澧兰沅芷,写行比伯夷的志向,写吉日良辰的春光,写千里之驹的奔跑,写那怀瑾握瑜的少年,还有在春光中乐不可言的少年。你要写女孩们请死记,守住你的边界感我越来越发现,很多人并没有边界感,也许是思想的限制,也许是觉得已经很熟了,也许本身大大咧咧。很多人问边界感是啥呢?我个人觉得它其实是个摸不着的东西,你感受不到它,它却无时无刻不存在早安美图心语,清新的早晨,灿烂的笑容,美好的今天,愿你开心举世都在追求成功的时候,我们虽不必追求失败,对成功却要有最好的心理准备,就好像在复天的时节准备冬衣一样。林清玄早安美图心语,清新的晨风,灿烂的笑容,迎接美好的一天。头条创作挑战赛暖不是乌克兰,俄军敲响警报得往另一个方向增兵了文君剑俄军在乌克兰进行了9个多月的军事行动,然而最近俄军却敲响警报,指出乌克兰不是最紧迫挑战,当下俄军需要往另一个方向增兵,并做好新战场出现的准备。据中新网报道,俄国防部刊物军事思最有钱的五位网红,一顿饭吃掉15万,创业两年住上汤臣一品?最有钱的五位网红,一顿饭吃掉15万,两年住上汤臣一品?你永远想不到网红们有多有钱有人一顿饭吃掉15万有人一块表抵上海两套房更有人大放厥词称自己能给马云刷破产他们为何如此猖狂现在的网每天经历16次日出日落,航天员在太空怎么生活?专家解答央广网北京12月2日消息(记者王迟王晶)11月30日7时33分,神舟十五号航天员乘组顺利进驻中国空间站,与神舟十四号航天员乘组首次实现太空会师。这是中国载人航天工程今年的第6次飞行吴亦凡胖成轮胎,服刑十三年后回加拿大,会被化学阉割吴亦凡事件终于赢来了大结局,经过长时间收集证据最终,吴亦凡被判了十三年,虽然大快人心,但是显然很多人对这种判决并不满意,甚至很多网友觉得判的太轻了,但是二妹得给大家科普一下,吴亦凡散文你是我最牵念的人翻阅一段美好的记忆,执笔一段过往,我在蝶恋花的清词里划去忧伤的字眼,写着想你的故事,写着你在时光里拓下的痕迹,写着我浮生若梦的日子。相思情,相思意,轻触琴弦,轻吟过往,凋谢是一种真日记11月28号标题是日期,随笔写写,也就不写标题党了。一看,28号了。马上12月,2022年的最后一个月。有个感觉,时间过得越来越快了,为啥捏?是不是成年后自力更生变幸福快乐了。小时候虽然不用咱一个人的顶级自律,是坚持这4件事专注当下与其沉浸在无法改变的过去,或是难以预知的未来,不如专注于每一个当下。任何事情都需要一个积累的过程,既不能急于求成,也不可放任自流。用好眼前的每一分每一秒,踏踏实实做好每件事