`
天使的左手
  • 浏览: 55917 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ClassLoader

    博客分类:
  • java
阅读更多
public class ClassLoaderTest
{
    /**
       Java的类加载器采用了一种父委托机制来加载需要的类.每个ClassLoader都关联一个父ClassLoader,
       除了BootstrapClassLoader(启动类加载器)外.Java默认实现了三个类加载器:
       BootstrapClassLoader(最顶层的类加载器),ExtClassLoader(扩展类加载器),AppClassLoader(系统类加载器),
       其中ExtClassLoader的父加载器是BootstrapClassLoader,而AppClassLoader的父加载器是
       ExtClassLoader.
       BootstrapClassLoader默认从sun.boot.class.path环境变量设置的路径加载类文件,
       ExtClassLoader默认从java.ext.dirs环境变量设置的路径加载类文件,AppClassLoader默认是从
       java.class.path环境变量设置的路径加载类文件.
       当一个类加载器试图加载一个类时,会先在自己的本地缓存(表达不是很恰当)中查找,如果之前已经加载过
       这个类,就直接返回.如果没找到就委托给父加载器去加载,没找到继续往上查找,
       也就是说一开始让最高层的父加载器加载这个类,父加载器加载成功,直接返回,并将这个类对象缓存起来,
       如果加载不了,就让第二层父加载器加载,直到找到自己,如果自己也不能加载这个类,抛出ClassNotFoundException
       
        因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
        考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态
        替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,
        因为String已经在启动时就被引导类加载器(BootstrapClassLoader)加载,
        所以用户自定义的ClassLoader永远也无法加载一个自己写的String,
        除非你改变JDK中ClassLoader搜索类的默认算法(重写loadClass方法)
       
       JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。
       只有两者同时满足的情况下,JVM才认为这两个class是相同的。
     */

    // 启动类加载器的类加载路径
    private static void getBootstrapClassPath2()
    {
        /**
         * 结果: file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/resources.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/rt.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/sunrsasign.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/jsse.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/jce.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/charsets.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/classes/
         */
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls)
        {
            System.out.println(url);
            // 获取没有被转义的路径
            // System.out.println(url.toURI().getPath());
        }
    }

    // 启动类加载器的类加载路径
    private static void getBootstrapClassPath()
    {
        // 直接从环境变量获取启动类加载器的类加载路径
        /**
         * 结果: C:\Program Files\Java\jdk1.6.0_17\jre\lib\resources.jar
         * C:\Program Files\Java\jdk1.6.0_17\jre\lib\rt.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\sunrsasign.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\jsse.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\jce.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\charsets.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\classes 自己添加的,JDK默认不包含这个目录
         */

        // 在VM参数中加入选项:-Xbootclasspath/a:c:\cl.jar
        // 表示在原有的启动类加载器的类加载路径后面加上一个c:\cl.jar包
        // 选项-verbose 可以输出虚拟机启动过程中类被加载的详细信息
        String bootstrapClassPath = System.getProperty("sun.boot.class.path");
        String[] parts = bootstrapClassPath.split(";");
        for (String part : parts)
            System.out.println(part);
    }

    private static void classLoaderHierarchy()
    {
        /**
         * 结果: Current class loader: sun.misc.Launcher$AppClassLoader@47858e
         * Parent class loader: sun.misc.Launcher$ExtClassLoader@19134f4 Parent
         * class loader: null
         */
        ClassLoader loader = ClassLoaderTest.class.getClassLoader();
        System.out.println("Current class loader: " + loader);
        while (loader != null)
        {
            loader = loader.getParent();
            System.out.println("Parent class loader: " + loader);
        }
    }
}
public class URLClassLoader extends ClassLoader
{/**
     * 自定义类加载器
     */
    public static void main(String[] args) throws Exception
    {
        String baseURL = "http://localhost:8080/rat/classes";
        URLClassLoader ucl = new URLClassLoader(baseURL, null);
        Class<?> clazz = ucl.loadClass("com.classloader.SimpleObj");
        System.out.println("class: " + clazz);
        //父加载器找不到SimpleObj,所以最终由我们自己定义的类加载器加载
        //class loader: com.classloader.URLClassLoader@1034bb5
        System.out.println("class loader: " + clazz.getClassLoader());

        //SimpleObj默认由AppClassLoader加载,此时SimpleObj存在classpath中
        //所以定义类加载器(最终执行类加载的那个类加载器)为AppClassLoader
        SimpleObj obj = new SimpleObj();
        System.out.println("class: " + obj.getClass());
        //class loader: sun.misc.Launcher$AppClassLoader@47858e
        System.out.println("class loader: " + obj.getClass().getClassLoader());

        //target的类文件是由我们自定义类加载器加载的
        //obj的类文件是由系统类加载器加载的 是两个不同的类型
        Object target = clazz.newInstance();
        System.out.println("target: " + target);
        Method m = clazz.getMethod("setObj", Object.class);
        System.out.println(m);
        //所以此时利用反射调用target对象的setObj会出现类型转异常
        //Caused by: java.lang.ClassCastException: com.classloader.SimpleObj 
        //cannot be cast to com.classloader.SimpleObj
        //at com.classloader.SimpleObj.setObj(SimpleObj.java:34)
        m.invoke(target, obj);
    }

    private String baseURL;

    public URLClassLoader(String baseURL)
    {
        this(baseURL, getSystemClassLoader());
    }

    public URLClassLoader(String baseURL, ClassLoader parent)
    {
        super(parent);
        this.baseURL = baseURL;
    }

    //loadClass中定义了类加载的规则,如果遍历完所有的父加载器后,都不能完成类的加载,
    //就会调用findClass方法去加载所要的类,所以实现自己的类加载器时,只要覆写findClass即可
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException
    {
        byte[] data = getClassData(name);
        if (data == null)
            throw new ClassNotFoundException(name);
        return defineClass(name, data, 0, data.length);
    }

    private byte[] getClassData(String name)
    {
        InputStream in = null;
        try
        {
            URL url = new URL(className2FilePath(name));
            in = url.openStream();
            byte[] buf = new byte[4 * 1024];
            int len = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            while (-1 != (len = in.read(buf)))
                baos.write(buf, 0, len);

            return baos.toByteArray();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                }
            }
        }
        return null;
    }

    private String className2FilePath(String name)
    {
        return baseURL + "/" + name.replace(".", "/") + ".class";
    }
}
分享到:
评论

相关推荐

    白色简洁风格的软件UI界面后台管理系统模板.zip

    白色简洁风格的软件UI界面后台管理系统模板.zip

    自动软包电芯极耳短路测试精切一体机sw17可编辑全套技术资料100%好用.zip

    自动软包电芯极耳短路测试精切一体机sw17可编辑全套技术资料100%好用.zip

    RuntimeException如何解决.md

    RuntimeException如何解决.md

    云链客服需要注意的事项

    定期分析系统的投资回报率(ROI)是确保企业在实施云链客服系统后获得实际效益的关键步骤。以下是一个系统的框架和方法,帮助您有效地进行投资回报率分析。 投资回报率(ROI)分析框架 一、定义投资回报率 投资回报率(ROI)是衡量投资效率的指标,通常通过以下公式计算: ROI= 成本 收益−成本 ​ ×100% 收益:通过实施系统所带来的直接经济利益,例如收入增加、成本节省等。 成本:系统的实施和运营成本,包括初始投资和持续运营费用。 二、确定收益来源 直接收益 销售增长:由于客服系统提升了客户满意度和响应速度,导致客户购买量增加。 客户保留率提高:系统帮助降低客户流失率,保持长期客户关系。 跨卖和追加销售:通过更好的客户互动和数据分析,提升交叉销售和追加销售的机会。 间接收益 运营效率提升:客服人员的工作效率提高,能够处理更多客户请求,减少人力成本。 品牌形象增强:客户体验的改善有助于提升品牌形象,吸引新客户。 客户忠诚度提升:满意的客户更可能成为回头客,提升长期收益。

    白色简洁风格的室内设计案例源码下载.rar

    白色简洁风格的室内设计案例源码下载.rar

    (177373454)html+css+js学习代码.zip

    html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+js学习代码 html+css+js学习代码html+css+js学习代码html+css+j

    三相逆变 单相 三相逆变器 SPWM -stm32主控(输入、输出具体可根据需要设定),本逆变器可以二次开发 本内容只包括 逆变程序,实现变频(0~100Hz)、变压调节,均有外接按键控制(使用

    三相逆变 单相 三相逆变器 SPWM ---stm32主控(输入、输出具体可根据需要设定),本逆变器可以二次开发。 本内容只包括 逆变程序,实现变频(0~100Hz)、变压调节,均有外接按键控制(使用C语言实现)。

    基于STM32单片机的激光雕刻机控制系统设计-含详细步骤和代码

    内容概要:本文详细介绍了基于STM32单片机的激光雕刻机控制系统的设计。系统包括硬件设计、软件设计和机械结构设计,主要功能有可调节激光功率大小、改变雕刻速率、手动定位、精确雕刻及切割。硬件部分包括STM32最小系统、步进电机驱动模块、激光发生器控制电路、人机交互电路和串口通信电路。软件部分涉及STM32CubeMX配置、G代码解析、步进电机控制、激光功率调节和手动定位功能的实现。 适合人群:对嵌入式系统和激光雕刻机感兴趣的工程师和技术人员。 使用场景及目标:① 适用于需要高精度激光雕刻的应用场合;② 为开发类似的激光雕刻控制系统提供设计参考。 阅读建议:本文提供了详细的硬件和软件设计方案,读者应结合实际应用场景进行理解,重点关注电路设计和代码实现。

    北航软件体系架构.7z

    北航软件体系架构.7z

    白色简洁风格的高端汽车预订企业网站源码下载.zip

    白色简洁风格的高端汽车预订企业网站源码下载.zip

    白色宽屏风格的时尚摄影图片网站模板下载.zip

    白色宽屏风格的时尚摄影图片网站模板下载.zip

    (31028834)大数据技术之Hadoop(入门).docx

    ### 大数据技术之Hadoop(入门)知识点详解 #### 第1章 大数据概论 ##### 1.1 大数据概念 大数据是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合。这些数据具有体量巨大、来源多样化、格式复杂等特点。 ##### 1.2 大数据特点(4V) **Volume(体量大)**:指的是数据量非常庞大。 **Velocity(速度快)**:指数据产生的速度极快。 **Variety(多样性)**:指数据类型多样,不仅限于结构化数据,还包括大量半结构化和非结构化数据。 **Value(价值密度低)**:尽管数据总量很大,但真正有价值的信息可能只占一小部分。 ##### 1.3 大数据应用场景 - **金融行业**:风险控制、精准营销、反欺诈等。 - **零售行业**:客户行为分析、库存管理优化等。 - **医疗健康**:疾病预测、个性化治疗方案制定等。 - **交通物流**:智能交通系统、物流路径优化等。 ##### 1.4 大数据发展前景 随着物联网、云计算等技术的发展,大数据的应用场景将会更加广泛。预计未来几年内,大数据技术将更加成熟,处理能力更强,为

    UnknownHostException(解决方案).md

    UnknownHostException(解决方案).md

    LP3_PLC程序培训_01.zip

    LP3_PLC程序培训_01.zip

    白色简洁风格的重型汽车销售企业网站源码下载.zip

    白色简洁风格的重型汽车销售企业网站源码下载.zip

    白色简洁风格的摄影图片模板下载.zip

    白色简洁风格的摄影图片模板下载.zip

    白色宽屏风格的农家乐有机蔬菜企业网站模板.rar

    白色宽屏风格的农家乐有机蔬菜企业网站模板.rar

    北航智能自主系统.7z

    北航智能自主系统.7z

    白色简洁风格的网络实验室CSS模板.zip

    白色简洁风格的网络实验室CSS模板.zip

    (175218226)利用仿真实现定时器设计的门铃

    门铃是日常生活中常见的一种设备,它通过发出声音来通知人们有访客或者有其他重要事件发生。在信息技术领域,特别是在嵌入式系统中,利用单片机设计定时器门铃是一项基础且实用的技术实践。单片机,即单片微型计算机,因其集成度高、成本低、应用广泛,常被用于各种控制系统的开发。本文将详细探讨如何使用单片机实现定时器门铃的设计。 我们需要了解单片机的基本结构。单片机通常包括CPU、存储器(ROM和RAM)、定时/计数器、输入/输出接口等组成部分。其中,定时/计数器是实现定时器功能的关键。它可以通过对内部时钟脉冲的计数来达到定时的效果,或者对外部事件的计数来实现计数功能。 在设计定时器门铃时,我们会用到单片机的定时器功能。定时器工作模式通常有多种,如自由运行模式、捕获模式、比较模式等。对于门铃应用,我们可能选择自由运行模式,设置一个预设的时间间隔,当定时器溢出时,触发中断,从而启动门铃音效。 实现门铃的代码主要包括以下几个部分: 1. 初始化定时器:这一步通常包括设置定时器的工作模式、初值、分频系数等。例如,我们可以选择定时器工作在自动重装载模式,并设定合适的初值,使得定时器在一定时间后溢出。 2. 中断

Global site tag (gtag.js) - Google Analytics