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

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

世乒赛伊藤美诚30吊打奥运亚军,日本女团晋级决赛与国乒争冠北京时间10月7日晚,成都世乒赛女团决赛名单正式出炉继世界排名第一的中国队30轻取中国台北队之后,世界排名第二的日本队也大获全胜,30横扫德国女乒晋级,所以冠军就将在国乒与日本之间好消息!王治郅找到新工作,拒绝姚明邀请,正式离开中国篮坛问如何每天都能收到如此有趣的体育原创资讯?答只需轻点右上角的关注按钮就能实现梦想。巴特尔王治郅和姚明合称中国的移动长城,他们是上个世纪90年代到00年代国内最出色的内线球员,不仅带中国女排迎战意大利队,蔡斌赛前发声,或继续重用1米98奇兵中国女排决战意大利队!蔡斌变阵霸气发声,198cm王牌驰援2022女排世锦赛第二轮比赛如火如荼,蔡斌带领球队斩获17分暂列E组第二,意大利女排19分暂列E组第一。在稍早前的比赛中,荒木由美子马云为见她一面曾6次前往日本,究竟两人有何关系?1983年,日本电视连续剧排球女将引进我国,一夜之间引起了许多国人的热烈追捧,当时我国女排取得了史无前例的五连冠,排球也成为全民运动,此时一部排球电视剧的横空出世,自然吸引了无数人马龙回应11比0全力以赴是最大的尊重北京时间10月6日,第56届世界乒乓球团体锦标赛第七比赛日,男团18决赛,由樊振东马龙王楚钦组成的中国队30击败印度队,顺利晋级八强。马龙在比赛中值得一提的是,在第二场男单对决中,连扳三局大逆转,这份王楚钦表情包请收好图集封面新闻记者陈羽啸摄影报道10月7日,中国男团30战胜瑞典男团晋级四强,比赛中,在樊振东马龙纷纷获胜后,第三个出战的王楚钦在先丢两局后连扳三局逆转,最终中国队以3比0淘汰对手晋级。赛场丨张本智和助日本男队晋级四强半决赛大概率上演中日对决今日(10月7日)下午3时,成都世乒赛团体赛男团14决赛再战一场,日本队3比1击败葡萄牙队,闯入半决赛。在今日早些时候结束的两场男团14决赛中,韩国队3比1逆转战胜中国香港队,德国世乒赛10。7赛报中国男队胜瑞典,女乒胜台北,10。8号两场中日战2022年10月7日,成都世界乒乓球团体锦标赛进入第八个比赛日,进行了男子团体14决赛和女子团体的半决赛,共六场精彩纷呈的较量。男子团体14决赛中国30瑞典这场堪比提前上演的决赛的喜上加喜!刘国梁获2个重要任命,走马上任,执掌世界乒联一把手成都世乒赛正打得如火如荼,中国男队和女队也双双挺进淘汰赛,向着最终的冠军奖杯,发起最有力的冲击。在成都世乒赛举行期间,国际乒联和世界乒联先后召开重要会议,决定了一些重要的人事任免,高诗岩2536,山东8673胜辽宁,郭艾伦1435难救主,辽宁2连败北京时间2022年10月7日,20222023赛季CBA季前赛第二比赛日展开多场比赛的争夺,在黄金时段进行的山东高速与辽宁本钢的比赛备受关注,最终经过4节比赛的鏖战,山东高速86比女生穿过膝靴时里面都穿袜子吗,如果穿的话穿的是什么样的袜子?过膝靴的长度就决定了妹子穿的时候一定要穿袜子。裹上丝袜的双腿能更轻松地伸进鞋子里,如果是光脚穿不穿得进去是首要问题,即使费劲穿进去脚也闷得难受我一般会穿同色系丝袜,比如灰色过膝搭灰
中老一家亲南欧江水电站中老员工共庆新春琅勃拉邦航拍国际在线报道(记者莫小玲)中国电建南欧江流域梯级水电项目位于老挝北部琅勃拉邦省和丰沙里省境内,是中企在海外首个全流域整体规划和投建的BOT项目,2021年9月全部建成投明天破五节,破五吃三样,人旺财也旺,三样分别指什么?快乐的时光总是短暂的,不知不觉新年就要过完了,明天就是正月初五,也就是我们所说的破五,一般说来,在除夕到正月初五期间,我们有很多禁忌要讲究。比如说不能倒垃圾,不能说不吉利的话,不能8。如何维持正常的肠道功能1营养均衡的膳食(一日三餐中包含蛋白质维生素矿物质脂肪酸膳食纤维等)2充足睡眠(可以维持正常的人体免疫力,睡眠不足免疫力低下会使细菌有乘虚而入的机会)3规律的作息(小孩身体发育尚未比贫穷更可怕的,是孩子没有规矩现在的孩子,你给他说一会儿出去干啥啥要怎么怎么样,他都会问为什么,家长说这是规矩,他都会小声嘟囔规矩规矩又是规矩,一副讨厌的表情!其实,规矩它是一直存在!自然有自然的规矩如四季轮回7。解决便秘的办法1合理服用乳果糖等纤维素药物(若服用量过大会出现腹泻样表现,要选择与孩子年龄相当的剂量)2合理服用益生菌益生元3正确使用开塞露(长期使用会产生心理依赖)4顽固性便秘需要就医查明原因如何帮助重度精神分裂症妈妈从一个爱抱怨的人,变成学会思考的人首先,从时间上这件事不是一蹴而就的,所以需要的时间也是相对漫长的。做好打持久战的心理准备,日子才有希望过得轻松快乐。其次,要考虑到想要解决这个问题是极有难度的,方法的多样性和有效性平安是福,提醒您和孩子安全过大年!健康幸福过新年(8)春节安全过大年春节是孩子们的开心时刻,家里都摆放着各类坚果糖果水果等,加上孩子们在一起打打闹闹,容易发生食物卡喉及异物吸入的情况。家长要注意防范,懂得如何处理。孩子好奇心强,安全意肌斜颈先天性肌斜颈是一侧胸锁乳突肌纤维性挛缩,颈部和头面部向患侧偏斜畸形,很多是由于胎儿臀位产产伤及牵拉等因素导致胸锁乳突肌损伤出血,血肿机化挛缩而形成,此外还有遗传,子宫内外感染等因素闪电日志洗澡是个技术活山幺闪电的幼儿期生活钟基本上保持一致,吃完饭喝完奶就是洗脸。睡觉醒来先伸懒腰,做个简短的磨爪运动,然后舔舐身体。妥妥一枚爱干净的崽!视频加载中不过布偶宝宝的毛是真的长。每次看闪电洗春晚10大热搜,岳云鹏凭实力,张若昀靠颜值,撒贝宁苏有朋最尴尬随着全国各地鞭炮声的奏响,新的一年也已经来到。与往年一样,每家每户在团圆之时,总是守着电视收看春晚,虽然近几年春晚节目质量总是褒贬不一,但也丝毫不影响大家的观看热情。与往届春晚一样贾玲2023年01月25日消息贾玲贾玲2023年01月25日消息贾玲没有参加2013年春晚?或许正走着一步大棋贾玲岳云鹏沈腾宋小宝四大喜剧团全接不了赵本山的班贾玲张小斐缺席2023年春晚贾玲怎么没有上今年春晚?