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

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()));   } }

在古代当1个平庸的皇子,和其他皇子处理好关系,会过得顺利吗?请大家把自己替换到这样一个历史角色。在古代,你是父皇眼里最平庸最胸无大志最一无是处的一个皇子。你的祖父是开国天子。祖父挂掉后,权臣操控庙堂,消灭了你的大叔二叔,你父皇继承大统,又消巴斯勒很惊讶拜仁解雇纳帅,球队又开始走向绿茵好莱坞时期直播吧3月26日讯前拜仁球员巴斯勒在接受sport的采访时表示,很惊讶拜仁解雇了主帅纳格尔斯曼。巴斯勒表示拜仁肯定是发生了一些严重的事情,我无法想象其他更多的事情了。因为在输掉一场争霸百年揭秘中国春秋时期的权力游戏(一)在中华历史上,春秋时期是一个极为重要的时代。而春秋时期的政治环境也异常复杂,各诸侯国为了争夺霸权,展开了激烈的争斗。这场历经百年的争霸,被后人称为春秋争霸。本文让我们一起进入春秋时问答尼罗河是否有像黄河那样频繁改道?问作为两大文明的起源地,尼罗河对埃及的意义丝毫不亚于黄河对华夏的重要性。但似乎很少有人注意到,这类纵观平原地带的大河,往往也伴随有巨大的破坏力。例如不定期发生的洪涝灾害,甚至会造成流浪的难民罗兴亚人(中)吞并阿拉干后,缅甸贡榜王朝与孟加拉接壤。19世纪初,英国驻威廉堡管辖区总督(管辖孟加拉,驻地在加尔各答)多次遣使赴缅,要求缅甸不得与英国殖民劲敌法国合作对英国开放港口允许英使驻留缅中年人为什么不快乐马德在允许自己虚度时光写下这么一段话,我慢慢明白了为什么我不快乐,因为我总是期待一个结果。看一本书期待它让我变得深刻,吃饭游泳期待它让我一斤斤瘦下来,发一条短信期待它被回复,对别人全职炒股能养家糊口吗熊市中赚钱养家的快乐!我从07年开始炒股到现在已经有16年了,以技术量价分析为主。自从2020年辞去公职,就开始正式炒股养家。当然,一开始是以开阔的心态去做的,希望多方面尝试,长线中线短线都试,都有赢输2022上合昆马跑者说跑出健康,跑出快乐海鸥翔集,鲜花相伴。3月26日,2022上合昆明马拉松激情开跑。万余名跑友聚首滇池畔,跑出新高度,追梦彩云南。经过角逐,来自肯尼亚的切鲁伊约特以2小时16分58秒夺得全程马拉松男子乡味丨山西静乐当洋庄稼有了乡土味编前语产业兴则农村兴,农村兴则国家旺。习近平总书记在2022年中央农村工作会议上强调,产业振兴是乡村振兴的重中之重,要落实产业帮扶政策,做好土特产文章。当前,全国各地发展农村特色产数字经济京北小城打造京津冀数字经济创新示范基地京北小城打造京津冀数字经济创新示范基地走进国家新型工业化产业示范基地图为位于承德县的华明服务外包产业园。承德县高新区管委会供图作为国家新型工业化产业示范基地之一,承德县高新区深入实叱咤笑坛七十载风云再起满堂彩黄俊英从艺70周年专题晚会昨晚上演羊城晚报全媒体记者黄宙辉通讯员伍尚文报道87岁高龄仍活跃在舞台第一线,2022年荣膺广东省文艺终身成就奖殊荣3月25日晚,笑坛风云录黄俊英从艺七十周年专题晚会(下称笑坛风云录晚会)
宝宝有点黄?预防新生儿黄疸,有些是孕期就要开始了宝宝出生后没几天,很多妈妈就发现宝宝的皮肤越来越黄,这难道就是传说中的新生儿黄疸吗?如果宝宝真的黄了,妈妈也不要太紧张。据不完全统计,大约60的新生儿和80的早产宝宝会在出生后的一宝宝发烧怎么办?因为疫情的原因,最近这些天估计很多宝妈都面临这个问题宝宝发烧了,去不去医院?那么,宝宝发烧了,如何处理?去不去医院主要看宝宝的具体情况,如果只是体温高,没有其他特殊情况,可以自行在储奶没注意这几点,宝宝容易腹泻!若说最适合宝宝的口粮是什么,答案肯定是母乳。因为母乳兼备经济实惠和营养全能两大特性。若想让宝宝多喝一口母乳,储奶是最好的方法。储奶指通过人工挤奶的方式,将多余的母乳吸出进行冷藏或冷mark点怎么制作?9个mark点定位原则,图文案例,带你搞定mark点大家好,我是百芯,可以叫我老百姓(老百芯)笑哭之后我会在这里和大家分享DFM可制造性分析PCB设计DFM工具,电路设计等相关的知识,请大家多多指教。今天给大家分享的是PCBmark口袋奇兵幸运翻翻卡最全攻略来了,看完帮你拿100橙碎半年一回的翻翻卡来了,文末有结论如何翻,可以直接划至文末。1翻翻卡基础规则,怎么玩?玩家第一次进入活动时会得到系统随机刷新3种卡组之一,消耗钻石可以翻卡随机获得奖励,一键翻卡获得当Steam注册captcha错误解决方法steam商城中玩家们可以尽情选购自己感兴趣的游戏,大受欢迎。虽然steam平台的人气的确很高,但目前也存在不少的问题。举个例子来说,很多玩家在注册steam账号时,系统总是提示C夏侯惇,三国中唯一可与吕布五五开的男人不能光打游戏,有空也要多了解一下历史。这段时间玩王者夏侯惇玩得可以,就去了解了一下他的历史资料。看完后,我发出一声感叹这就是唯一可以和吕布五五开的男人啊!相信很多人和我一样,是从三为什么阳了后,会出现刀片嗓?不少小阳人分享称,感染后喝口水像吞刀片,咽口水像吞玻璃渣,这是为什么呢?这主要是因为声带和声门周围的黏膜充血水肿导致的,这种情况一般是发生在病程的中后期。那如何缓解刀片嗓?1多喝水咳嗽最怕喝这汤!每天煮一锅,省钱又实用,冬天少生病进入十二月以来,随着天气越来越冷,我们的身体会特别疲劳,甚至会出现失眠的情况,身体特别虚弱,四肢无力,气色也越来越差。由于我们正处于流感高发的季节,平常如果不注意调理,身体的抵抗力体虚对于夫妻性福生活会有影响吗?听听医生怎么说(第五篇)日常体检中总是发现报告单上出现脂肪肝的诊断,哎可能自己吃的太油了吧明天和意外永远不知道哪一个先会到来,早上起来发现自己动不了了!对于以上两种情况来讲和自身的血瘀体质往往有一定的关系感冒之后咳嗽久久不愈,吃点啥才好?冬季天气寒冷,人们很容易患上感冒咳嗽。加之近期各地新冠肆虐,咳嗽往往迁延难愈,严重时还会导致肺炎。按照中医理论,感冒咳嗽的原因有风寒风热风燥体虚等,采取的治疗方法也不相同。本文介绍