第一节我们说过一句话:所有的Java虚拟机实现必须在每个类或接口被Java程序“ 首次主动使用”时才初始化他们

但类加载器却不是这样:类加载器不需要等到某个类“被首次主动使用”时才加载类

两句话的区别就在于红线标注的地方,所以我们要明确一点ClassLoader只负责类的加载,即 加载  》 连接 》初始化 的第一步

由上一节我们知道,jvm有三种加载器,每种加载器负责特定目录的类。根类加载器(BootStrap)和扩展加载器(Extension)不必说,它们负责加载的都是特定目录的类,而且这些类是固定的,我们不能说我们把自己编写的类加到java.lang目录下就能使这个类被根类加载器加载,那样就太不安全了。因为加载的类是固定的就很好理解,但是系统类加载器(System)就比较不好理解了,它是加载classpath定义的目录下的类。而且我们知道classpath路径是可以自定义的,也就是说它可以加载任意目录的类,只要我们在classpath下指定了该目录。

比如我们安装好jdk配置好环境变量之后,我们就可以在任意位置使用javac命令和java命令,但是你有没有想过,我们并没有指定类加载的路径,为什么我们在任何地方都能加载到目标类文件呢。原因很简单就是环境变量的配置,我们一般回配置两个参数path和classpath。path的作用是让我们在任意目录下都能找到javac和java命令,但是单单找到命令是不够的,有命令没有类文件一样白搭,所以classpath的设置就是帮我们找到类文件,classpath一般这样设置     .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar  。注意最开始的那个点,最不起眼却最重要,它代表当前文件夹,当我们在一个很偏僻的文件夹使用javac命令编译java文件,这个文件夹就是我们工作的当前文件夹,jvm就会到path下去寻找javac命令,path配置正确找到命令。然后到classpath下去寻找class文件,然后就发现了  "  .  " ,于是就会到当前文件夹下寻找,一下就找到了,类编译就完成了,java命令一样。

现在系统类加载器(System)已经很清楚了。那我们能不能自己编写自己的类加载器呢,答案是肯定的,当然,类加载很复杂,要我们从零做起是不现实的,我们只能根据已有的类加载器进行包装,定制自己的ClassLoader

自定义类加载器分为以下几个步骤:

1、定义类。继承ClassLoader

2、重写ClassLoader的 findClass方法
就是这么简单,下面是我自己写的自定义类加载器例子
 
 
public class MyClassLoader extends ClassLoader{

    private String path;   //类的加载路径
    private String name;   //类加载器的名字

    public MyClassLoader() {}
    public MyClassLoader(String path,String name){
        this.path = path;
        this.name = name;
    }

    //用于寻找类文件
    public Class findClass(String name) {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }

    //用于加载类文件
    private byte[] loadClassData(String name) {

        name = path + name + ".class";
        //使用输入流读取类文件
        InputStream in = null;
        //使用byteArrayOutputStream保存类文件。然后转化为byte数组
        ByteArrayOutputStream out = null;
        try {
            in = new FileInputStream(new File(name));
            out = new ByteArrayOutputStream();
            int i = 0;
            while ( (i = in.read()) != -1){
                out.write(i);
            }

        }catch (Exception e){}
        finally {
            try {
                out.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        return out.toByteArray();

    }

    public String getName() {
        return name;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

  然后调用

public static void main(String[] args) {
        MyClassLoader m = new MyClassLoader("/home/fanjie/code/","classLoad1");

        Class c = m.findClass("Hello");
        System.out.println(c.getClassLoader());

    }

  结果 : classLoader.MyClassLoader@60e53b93

 

jvm学习三:自定义ClassLoader的更多相关文章

  1. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  2. JVM学习三:JVM之类加载器之连接分析

    学习完类加载之加载篇后,让我们继续来看加载之连接,连接分为三个步骤:验证.准备和解析三步,我们将一一分析之. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 类加载完毕之后进入 ...

  3. JVM学习三:JVM之垃圾收集器及GC参数

    一.堆的回顾 新生代中的98%对象都是"朝生夕死"的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用E ...

  4. JVM学习--(三)配置参数

    JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...

  5. JVM学习(三):垃圾回收算法

    局部性原理和分代回收思想 大学学习操作系统或者计算机组成原理的时候都提到一个重要概念,叫局部性原理. 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小 ...

  6. Struts入门学习(三)---自定义类型转换器

    类型转换器是将浏览器传递的参数进行转换为了与服务器端的参数匹配,先举个例子如果我们想往服务器传递日期类型的参数时我们要怎么让浏览器传过去的让服务器明白 我们新建一个类 ConverterTest.ja ...

  7. JVM学习三:静态分派

    所有依赖静态类型来定位方法的执行版本的分派动作成为静态分派,静态分派典型的应用场景是方法的重载.在编译阶段,javac编译器会根据参数的静态类型决定使用哪个重载版本,但很多种情况下这个版本并不是“唯一 ...

  8. JVM学习一:JVM之类加载器概况

    18年转眼就3月份都快结束了,也就是说一个季度就结束了:而我也因为年前笔记本坏了,今天刚修好了,那么也应该继续学习和博客之旅了.今年的博客之旅,从JVM开始学起,下面我们就言归正传,进入正题. 一.J ...

  9. JVM——三个ClassLoader详解

    类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java执行时系统组件,它负责在运行时查找和装入Class字节码文件.JVM在运行时会产生三个ClassLoader: ...

随机推荐

  1. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

    PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语言是 ...

  2. 理解Express中间件

    阅读目录 一:body-parser中间件 二:cookie-parser中间件 三:express-session 中间件 四:理解使用morgan记录操作日志 回到顶部 一:body-parser ...

  3. Linux下NTP服务器配置

    简介 原理 配置ntp服务器 进行同步 一.简介 在计算时间的时候,最准确的计算应该是使用『原子震荡周期』所计算的物理时钟了( Atomic Clock, 也被称为原子钟 ),这也被定义为标准时间(I ...

  4. 洛谷 P1396 营救

    题目链接 https://www.luogu.org/problemnew/show/P1396 题目描述 “咚咚咚……”“查水表!”原来是查水表来了,现在哪里找这么热心上门的查表员啊!小明感动的热泪 ...

  5. JAVA体系的线程的实现,线程的调度,状态的转换

    java体系中线程的实现 1.使用内核线程实现 内核线程就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操作调度器对线程进行调度,并负责将线程的任务映射到各个处理器上,每个内核 ...

  6. java中的异常区分

    在上图中,粉红色的部分为受检查的异常,其必须被try{}catch语句块所捕获,或者在方法中向外抛出异常 绿色的异常为运行时异常,需要程序员自行分辨是否要解决异常或者抛出异常,例空指针数组下标越界等等 ...

  7. RocketMQ环境搭建

    1 源码下载 wget http://mirror.bit.edu.cn/apache/rocketmq/4.2.0/rocketmq-all-4.2.0-bin-release.zip unzip ...

  8. Spring Aop: 关于继承和execution target this @annotation

    1.多态 target指通过这个对象调用的方法   (匹配标识对象的所有方法)  getMethod() this指调用这个对象的方法 (匹配标识对象实现的方法) getDeclaredMethod( ...

  9. Tensorflow实例:利用LSTM预测股票每日最高价(一)

    RNN与LSTM 这一部分主要涉及循环神经网络的理论,讲的可能会比较简略. 什么是RNN RNN全称循环神经网络(Recurrent Neural Networks),是用来处理序列数据的.在传统的神 ...

  10. dp方法论——由矩阵相乘问题学习dp解题思路

    前篇戳:dp入门——由分杆问题认识动态规划 导语 刷过一些算法题,就会十分珍惜“方法论”这种东西.Leetcode上只有题目.讨论和答案,没有方法论.往往答案看起来十分切中要害,但是从看题目到得到思路 ...