`

类加载器模拟

    博客分类:
  • Java
 
阅读更多

类版本1

package com.classLoad.version1;

public class Version {
    public void testVersion()
    {
        System.out.println("我是版本1");
    }
}

类版本2

package com.classLoad.version2;

public class Version {
    public void testVersion()
    {
        System.out.println("我是版本2");
    }
}

 

类加载器1

public class ClassLoad_1 extends ClassLoader {
   
     // 读入源文件转换为字节数组 
    private byte[] getSource(String filename) { 
        File file = new File(filename); 
        int length = (int) file.length(); 
        byte[] contents = new byte[length]; 
        FileInputStream fis = null; 
        try { 
            fis = new FileInputStream(file); 
            int r = fis.read(contents); 
            if (r != length) { 
                throw new IOException("IOException:无法读取" + filename); 
            } 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } finally { 
            try { 
                if (fis != null) { 
                    fis.close(); 
                } 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } 
        } 
        return contents; 
    } 
 
    // 编译文件 
    public boolean compile(String javaFile) { 
        System.out.println("正在编译" + javaFile); 
        int ret = 0; 
        try { 
            // 调用系统命令编译文件 
            Process process = Runtime.getRuntime().exec("javac " + javaFile); 
            process.waitFor(); 
            ret = process.exitValue(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        return ret == 0; 
    } 
 
    // 重写findclass 
    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
        Class<?> clazz = null; 
        // 将文件的.替换为/,例如com.lyl.reflect.Reflect被替换为com/lyl/reflect/Reflect 
        String fileStub = name.replace(".", "/"); 
        String path =  System.getProperty("user.dir");

        //可以理解为不同路径下的同名类
        fileStub = path + "\\bin\\com\\classLoad\\version1\\" + fileStub;
        // java源文件名 
        String javaFileName = fileStub + ".java"; 
        // 编译后的class文件名 
        String classFileName = fileStub + ".class"; 
        File javaFile = new File(javaFileName); 
        File classFile = new File(classFileName); 
        // 当指定JAVA源文件存在,且class文件不存在, 
        // 或者java源文件的修改时间比class文件修改时间晚则重新编译 
        if (javaFile.exists() 
                && (!classFile.exists() || javaFile.lastModified() > classFile 
                        .lastModified())) { 
            // 如果编译失败,或者class文件不存在 
            if (!compile(javaFileName) || !classFile.exists()) { 
                throw new ClassNotFoundException("ClassNotFoundException:" 
                        + javaFileName); 
            } 
        } 
        // 如果CLASS文件按存在,系统负责将该文件转换成Class对象 
        if (classFile.exists()) { 
            byte[] raw = getSource(classFileName); 
            // 将ClassLoader的defineClass方法将二进制数据转换成Class对象 
            int divindex = name.indexOf("\\"); 
            String javafilename = null; 
            // 如果是某个盘里面的文件,要去掉文件的盘符 
            if (divindex != -1) { 
                javafilename = name.substring(divindex + 1, name.length()); 
            } 
            // 将字节数组转换为class实例 
            clazz = defineClass(javafilename, raw, 0, raw.length); 
        } 
        // 如果clazz为null,表明加载失败,则抛出异常 
        if (clazz == null) { 
            throw new ClassNotFoundException(name); 
        } 
        return clazz; 
    } 
}

类加载器2

public class ClassLoad_2 extends ClassLoader {
   
     // 读入源文件转换为字节数组 
    private byte[] getSource(String filename) { 
        File file = new File(filename); 
        int length = (int) file.length(); 
        byte[] contents = new byte[length]; 
        FileInputStream fis = null; 
        try { 
            fis = new FileInputStream(file); 
            int r = fis.read(contents); 
            if (r != length) { 
                throw new IOException("IOException:无法读取" + filename); 
            } 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } finally { 
            try { 
                if (fis != null) { 
                    fis.close(); 
                } 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } 
        } 
        return contents; 
    } 
 
    // 编译文件 
    public boolean compile(String javaFile) { 
        System.out.println("正在编译" + javaFile); 
        int ret = 0; 
        try { 
            // 调用系统命令编译文件 
            Process process = Runtime.getRuntime().exec("javac " + javaFile); 
            process.waitFor(); 
            ret = process.exitValue(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        return ret == 0; 
    } 
 
    // 重写findclass 
    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
        Class<?> clazz = null; 
        // 将文件的.替换为/,例如com.lyl.reflect.Reflect被替换为com/lyl/reflect/Reflect 
        String fileStub = name.replace(".", "/"); 
        String path =  System.getProperty("user.dir");

        //可以理解为不同路径下的同名类

        fileStub = path + "\\bin\\com\\classLoad\\version2\\" + fileStub;
        // java源文件名 
        String javaFileName = fileStub + ".java"; 
        // 编译后的class文件名 
        String classFileName = fileStub + ".class"; 
        File javaFile = new File(javaFileName); 
        File classFile = new File(classFileName); 
        // 当指定JAVA源文件存在,且class文件不存在, 
        // 或者java源文件的修改时间比class文件修改时间晚则重新编译 
        if (javaFile.exists() 
                && (!classFile.exists() || javaFile.lastModified() > classFile 
                        .lastModified())) { 
            // 如果编译失败,或者class文件不存在 
            if (!compile(javaFileName) || !classFile.exists()) { 
                throw new ClassNotFoundException("ClassNotFoundException:" 
                        + javaFileName); 
            } 
        } 
        // 如果CLASS文件按存在,系统负责将该文件转换成Class对象 
        if (classFile.exists()) { 
            byte[] raw = getSource(classFileName); 
            // 将ClassLoader的defineClass方法将二进制数据转换成Class对象 
            int divindex = name.indexOf("\\"); 
            String javafilename = null; 
            // 如果是某个盘里面的文件,要去掉文件的盘符 
            if (divindex != -1) { 
                javafilename = name.substring(divindex + 1, name.length()); 
            } 
            // 将字节数组转换为class实例 
            clazz = defineClass(javafilename, raw, 0, raw.length); 
        } 
        // 如果clazz为null,表明加载失败,则抛出异常 
        if (clazz == null) { 
            throw new ClassNotFoundException(name); 
        } 
        return clazz; 
    } 
}

测试类

public class Test {
    // 定义主方法 
    public static void main(String[] args) throws ClassNotFoundException, 
            SecurityException, NoSuchMethodException, IllegalArgumentException, 
            IllegalAccessException, InvocationTargetException, InstantiationException { 
       
        ClassLoader ccl1 = new ClassLoad_1();
        ClassLoader ccl2 = new ClassLoad_2();
       
        // 加载需要运行的类 
        Class<?> clazz1 = ccl1.loadClass("Version");
        Class<?> clazz2 = ccl2.loadClass("Version");
        Method main1 = clazz1.getMethod("testVersion"); 
        Object o1 = clazz1.newInstance();
        main1.invoke(o1);
        Method main2 = clazz2.getMethod("testVersion"); 
        Object o2 = clazz2.newInstance();
        main2.invoke(o2);
    } 
}

 

输出数据:

我是版本1
我是版本2

 

 

 

分享到:
评论

相关推荐

    PE加载器源码.rar

    《深入理解PE加载器:基于VC++的源码解析》 PE(Portable Executable)加载器是Windows操作系统中至关重要的组件,它负责将可执行文件(.exe或.dll)从磁盘加载到内存中并执行。这个过程包含了众多复杂的步骤,如...

    Java Unit Test 和 XML 类加载器

    标题“Java Unit Test 和 XML 类加载器”涉及的是在Java编程中进行单元测试以及XML类加载器的相关知识。这两部分是Java开发中的重要概念,尤其是对于软件质量和可维护性而言。 首先,Java Unit Test,也称为单元...

    classloader的简单实现

    在给定的"类加载器的简单实现"项目中,我们看到一个开源的C++版本的类加载器尝试模拟Java的类加载机制。 虽然这里提到的是C++实现,但为了深入理解类加载器的工作原理,我们可以首先回顾一下Java中的类加载器机制。...

    ISO启动加载器ISO启动加载器ISO启动加载器

    ISO启动加载器的工作原理是模拟一个虚拟光驱,它能够读取ISO文件并将其内容呈现在操作系统的眼前,就像真的有光盘插入光驱一样。这种技术被称为“虚拟化”或“模拟”,它使得用户能够在不改变硬件配置的情况下,从...

    VMware镜像文件加载器

    VMware镜像文件加载器是虚拟化技术领域中一个重要的工具,主要负责在VMware平台上加载和管理虚拟机的磁盘镜像文件。VMware是一款流行的虚拟化软件,它允许用户在同一台物理计算机上运行多个独立的操作系统实例,每个...

    易语言学习-PE加载器(PeLoader)支持库版.zip

    在易语言的学习过程中,"PE加载器(PeLoader)支持库版"是一个重要的概念,它涉及到Windows操作系统中可执行文件(.exe或.dll)的加载机制。 PE(Portable Executable)是Windows操作系统中的可执行文件格式,包含了...

    金山快盘加载器

    【金山快盘加载器】是针对金山快盘服务停运后,用户可能遇到的问题而设计的一款辅助工具。金山快盘,原名Kanbox,是由金山软件推出的一种云存储服务,旨在提供便捷的数据备份和同步功能,让用户可以随时随地访问自己...

    antsword蚁剑の加载器&源码

    加载器通常是一个可执行文件,用户通过加载器来启动AntSword,进行后续的Web渗透测试工作。加载器的快速响应和稳定运行对于整个工具的效能至关重要。由于在线下载源码速度较慢,提供本地的加载器可以极大地提高工作...

    《 从NoSuchMethodError看jvm编译和class加载方式》的测试项目代码

    JVM(Java虚拟机)采用“双亲委派模型”加载类,即当一个类被加载时,它会首先尝试由启动类加载器(Bootstrap ClassLoader)加载,如果该类不在启动类加载器的路径中,则会委托给扩展类加载器(Extension ...

    class-loader测试工程

    这个“class-loader测试工程”可能是为了模拟和测试上述的各种情况,例如测试双亲委派模型、自定义类加载器行为、类的加载顺序以及类加载器之间的关系。通过这样的工程,开发者可以更好地理解和掌握Java平台的类加载...

    Java虚拟机模拟实现

    5. **类加载器的双亲委派模型**:当一个类加载器接收到加载类的请求时,它首先会委托给父加载器,只有当父加载器无法加载时,子加载器才会尝试加载,这种设计避免了类的重复加载和保证了类的唯一性。 6. **异常处理...

    Java反射动态加载实例类

    - `java.lang.reflect.Constructor`:表示类的构造器。 #### 二、动态加载实例类 在给定文件的代码示例中,我们看到一个名为`Refelection`的类,该类使用反射动态加载了一个名为`Student`的实例类。具体步骤如下:...

    电子功用-抽油机电动机动态负荷模拟加载系统及模拟加载方法

    硬件部分可能包括电力电子设备(如变频器)、模拟负载装置以及各种传感器等,用于实时模拟抽油机在不同阶段的负荷变化。软件控制部分则负责根据预设的模拟工况或实时采集的数据,调整加载系统的参数,以实现对电动机...

    android J2ME加载器 可以在android机上运行java游戏

    J2ME加载器的工作原理主要是通过模拟Java虚拟机(JVM)来实现的。Android原生支持的是Dalvik虚拟机,用于运行Android应用的APK文件。而J2ME加载器则创建了一个环境,使得Java bytecode能够在这个环境中被执行,就像...

    模拟JTAG加载CPLD的源码及说明文档。

    总的来说,模拟JTAG加载CPLD的实践是一个深入学习嵌入式系统、数字电路和编程技巧的好机会。它不仅要求对硬件有深入理解,还需要掌握微控制器编程和通信协议的知识。通过这样的实践,你可以提升自己在硬件开发领域的...

    Avlgomgr启动项加载器

    此外,镜像加载器还可以帮助用户在不需物理软盘的情况下,通过模拟软盘驱动器来加载软盘映像,这对于那些需要老式软盘驱动程序的软件来说非常有用。 Avlgomgr.exe是这个工具的主要执行文件,它包含了所有上述功能的...

    模拟Cydia加载过程

    【标题】:“模拟Cydia加载过程” 在iOS设备上,Cydia是一款广为人知的第三方应用商店,它允许用户安装未经Apple官方认可的软件和插件。本话题将深入探讨如何模拟Cydia的加载过程,这涉及到前端开发技术以及与Cydia...

    从一个小例子来看动态卸载class

    当不再需要`MyClass`时,我们可以通过丢弃`MyClassLoader`实例来模拟类的“卸载”。因为类加载器不再引用加载的类,JVM的垃圾回收机制最终会回收这些类的实例,尽管Class对象本身不会被卸载。然而,如果其他地方仍有...

    loader constraints测试

    5. **故障注入**:测试过程中,可能会模拟各种故障场景,如父加载器失败、类找不到等,来检验加载器的健壮性和恢复机制。 6. **性能和内存消耗**:类加载过程对系统的性能和内存使用也有影响。测试应考虑在大量类...

    powermock源码学习 支持模拟静态方法、构造函数、final类和方法、私有方法以及移除静态初始化器的模拟工具

    PowerMock的核心功能在于其能够通过提供定制的类加载器和应用一些字节码操作技巧,实现对静态方法、构造方法、私有方法和final方法的模拟。例如,在进行单元测试时,有时候我们并不希望测试数据进入实际的数据库,...

Global site tag (gtag.js) - Google Analytics