Java 自定义 ClassLoader 实现 JVM 类加载
发布日期:2021-06-29 09:29:05 浏览次数:2 分类:技术文章

本文共 3949 字,大约阅读时间需要 13 分钟。

定义需要加载的类

为了能够实现类加载,并展示效果,定义一个Hello类,再为其定义一个sayHello()方法,加载Hello类之后,调用它的sayHello()方法。

public class Hello {    public static void sayHello(){        System.out.println("Hello,I am ....");    }}

定义类加载器

自定义加载器,需要继承ClassLoader,并重写里面的protected Class findClass(String name) throws ClassNotFoundException方法。

import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.lang.reflect.Method;import java.nio.MappedByteBuffer;import java.nio.channels.FileChannel;import java.nio.channels.FileChannel.MapMode;public class MyClassLoader extends ClassLoader {    /**     * 重写父类方法,返回一个Class对象     * ClassLoader中对于这个方法的注释是:     * This method should be overridden by class loader implementations     */    protected Class
 findClass(String name) throws ClassNotFoundException {        Class clazz = null;        String classFilename = name + ".class";        File classFile = new File(classFilename);        if (classFile.exists()) {            try (FileChannel fileChannel = new FileInputStream(classFile)                    .getChannel();) {                MappedByteBuffer mappedByteBuffer = fileChannel                        .map(MapMode.READ_ONLY, 0, fileChannel.size());                byte[] b = mappedByteBuffer.array();                clazz = defineClass(name, b, 0, b.length);            } catch (IOException e) {                e.printStackTrace();            }        }        if (clazz == null) {            throw new ClassNotFoundException(name);        }        return clazz;    }    public static void main(String[] args) throws Exception{        MyClassLoader myClassLoader = new MyClassLoader();        Class clazz = myClassLoader.loadClass(args[0]);        Method sayHello = clazz.getMethod("sayHello");        sayHello.invoke(null, null);    }}

编译需要加载的类文件

类加载的时候加载的是字节码文件,所以需要预先把定义的Hello类编译成字节友文件。

javac Hello.java

验证字节码文件是否编译成功,利用二进制文件查看器查看我们编译之后的文件,样式如下:

0000000 177312 137272 000000 032000 016000 000012 000006 0044160000020 007400 010000 000010 005021 011000 011400 000007 0034240000040 012400 000001 036006 067151 072151 000476 001400 0244500000060 000526 002000 067503 062544 000001 046017 067151 0471450000100 066565 062542 052162 061141 062554 000001 071410 0745410000120 062510 066154 000557 005000 067523 071165 062543 0645060000140 062554 000001 044012 066145 067554 065056 073141 0061410000160 003400 004000 000007 006026 013400 014000 000001 0440170000200 066145 067554 044454 060440 020155 027056 027056 0000070000220 006031 015000 015400 000001 044005 066145 067554 0000010000240 065020 073141 027541 060554 063556 047457 065142 0615450000260 000564 010000 060552 060566 066057 067141 027547 0745230000300 072163 066545 000001 067403 072165 000001 046025 0605520000320 060566 064457 027557 071120 067151 051564 071164 0605450000340 035555 000001 065023 073141 027541 067551 050057 0645620000360 072156 072123 062562 066541 000001 070007 064562 0721560000400 067154 000001 024025 065114 073141 027541 060554 0635560000420 051457 071164 067151 035547 053051 020400 002400 0030000000440 000000 000000 001000 000400 003400 004000 000400 0044000000460 000000 016400 000400 000400 000000 002400 133452 0004000000500 000261 000000 000001 000012 000000 000006 000001 0000000000520 000002 000011 000013 000010 000001 000011 000000 0000450000540 000002 000000 000000 131011 001000 001422 000266 1304040000560 000000 000400 005000 000000 005000 001000 000000 0020000000600 004000 002400 000400 006000 000000 001000 0064000000616

编译自定义的类加载器并执行程序

//编译代码javac MyClassLoader.java//当然我们也可以同时编译我们所有的java源文件javac *.java

执行成功之后,我们用下面的语句执行代码,测试是否成功,并查看结果

java MyClassLoader Hello//运行结果Hello,I am ....

当程序按照预期显示,就证明我的自定义类加载器成功了。

总结

通过上面的程序代码,简单的实现JVM的类加载过程,知道了程序运行的一点流程。但是在编写的时候有如下坑需要注意

  • 类文件不需要指定包,否则加载的时候我们需要额外的处理,把包中的"."替换成文件系统的路径"/"。

  • 需要加载的Hello类中的反射调用的方法要用static修饰,这样invoke的时候第一个参数才可以使用null关键字代替,否则需要创建一个对应的类实例。

    官方文档中有这样一句话If the underlying method is static, then the specified obj argument is ignored. It may be null.

转载地址:https://blog.csdn.net/zl1zl2zl3/article/details/87070854 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Integer判断相等,到底该用==还是equals
下一篇:线下门店场景化互动类产品浅析

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月30日 19时55分48秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

Atitit 效率提升法细则 v3 t028.docx Atitit 提升效率细则 目录 1. 目标 2 1.1. 配置化增加扩展性 尽可能消除编译 方便增加 调整业务逻辑 2 1.2. 统一接口 2019-04-29
Atitit 工程师程序员技术级别对应表与主要特征 P1--p6 说明 类别 职称 对应技术标志 P5 高级工程师 工程师类 一般四五年 P6 资深开发 工程师类 78年经历 P7 P7 2019-04-29
paip.activex控件在WEB中使用流程与工具 2019-04-29
paip.软件及网站项目开发效率低下的思索与改进 2021-07-02
Atitit 可移植性之道attilax著 2019-04-29
paip.截屏功能流程说明 2019-04-29
Atiitt uke兼wag集团2017年度成果报告总结 attilax著 1. 组织机构进一步完善 8大首席部门 1 2. 事业部进一步完善,以及一百多个事业部了 1 3. 企业文化进一步完善 1 2019-04-29
Atititi ui之道 attilax著 v3 s11.docx 1. 概览 2 1.1. 软件设计可分为两个部分:编码设计与UI设计 2 2. 用户界面设计的三大原则是:置界面于用户的控制之下; 2019-04-29
Atitit 集团与个人的完整入口列表 attilax的完整入口 1. 集团与个人的完整入口列表 1 2. 流量入口概念 2 3. 流量入口的历史与发展 2 1.集团与个人的完整入口列表 2019-04-29
Atitit 网络编程之道 2019-04-29
Atiitt attilax掌握的前后技术放在简历里面.docx 2019-04-29
Atiitt 文档处理之道 attilax著 2019-04-29
Atiitt 可视化 报表 图表之道 attilax著 Atitit.可视化与报表原理与概论 1. 信息可视化 1 2. Gui可视化 2 2.1. atitit 知识的可视化.docx 2 2019-04-29
paip.c#图片裁剪 2019-04-29
paip.html 及css调试工具---debugbar 2019-04-29
paip.项目开发效率提升之思索 2019-04-29
paip.项目开发效率提升之思索 2019-04-29
Atitit spring5 集成 mybatis 注解班 2019-04-29
Atitit springboot mybatis spring 集成 Springboot1.4 mybatis3.4.6 /springbootMybatis 目录 1.1. 设置map 2019-04-29
Atitit 模板引擎总结 目录 1. 模板引擎 1 2. 常见模板步骤 1 2.1. 1)定义模板字符串 1 2.2. 2)预编译模板 2 2.3. 渲染模板 2 3. 流程渲染 if el 2019-04-29