Java的设计初衷是主要面向嵌入式领域,对于自定义的一些类,考虑使用依需求加载原则,即在程序使用到时才加载类,节省内存消耗,这时即可通过类加载器来动态加载。

如果你平时只是做web开发,那应该很少会跟类加载器打交道,但如果你想深入学习tomcat服务器的架构,它是必不可少的。所谓类加载器,就是用于加载Java类到Java虚拟机中,它负责读取Java字节码,并转换成java.lang.Class类的一个实例,使字节代码.class文件得以运行。一般类加载器负责根据一个指定的类找到对应的字节代码,然后根据这些代码定义成一个Java类,另外还负责加载资源,包括图像文件和配置文件。

类加载器在实际使用中给我们带来的好处是,它可以使Java类动态地加载到JVM并运行,即可在程序运行时再加载类,提供了很灵活的动态加载方式。例如我们熟悉的Applet,从远程服务器下载字节码到客户端动态加载到JVM便可以运行。

在Java的庞大体系中,可以将系统分为三种类加载器,分别是:

①   启动类加载器(Bootstrap ClassLoader):加载对象是Java核心库,把一些关键的Java类加载进JVM,这个加载器使用原生代码(C/C++)实现的,并不是继承java.lang.ClassLoader,它是所有其他类加载器的最终父加载器,负责加载<JAVA_HOME>/jre/lib目录下且被JVM指定的类库,其实它属于JVM整体的一部分,JVM一启动就将这些指定的类加载到内存中,避免以后过多的I/O操作,提高系统的运行效率。启动类加载器无法被Java程序直接使用。

②   扩展类加载器(Extension ClassLoader):加载的对象为Java的扩展库,即加载<JAVA_HOME>/jre/lib/ext目录里面的类。这个类由上面的Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader并非用Java实现,已经脱离了Java体系,所以如果尝试调用扩展类加载器的getParent()方法获取父加载器会得到null,但它的父类加载器是Bootstrap ClassLoader。Java中可以直接使用扩展类加载器。

③   应用程序类加载器(Application  ClassLoader):亦叫系统类加载器(System ClassLoader),它负责加载用户类路径(CLASSPATH)指定的类库,如果程序没有自己定义类加载器,就默认使用应用程序类加载器。它也由Bootstrap ClassLoader加载,但它的父加载类被设置成了Extension ClassLoader。如果要使用这个加载器,可通过ClassLoader.getSystemClassLoader()获取。

假如有一天你心血来潮也想自己写一个类加载器,那么你只需要继承java.lang.ClassLoader类即可。于是可以用下面的图2-4-1来清晰表示出各种类加载器的关系,Bootstrap ClassLoader是最根本的类加载器,其不存在父类加载器,Extension ClassLoader由Bootstrap ClassLoader加载,所以它的父类加载器是Bootstrap ClassLoader,Application ClassLoader也是由Bootstrap ClassLoader加载,但它的父加载器被指向了Extension
ClassLoader,而其他所有用户自定义的类加载器都由Application ClassLoader加载。

由此可以看出越重要的类加载器就越早被JVM载入,这是考虑到安全性,因为先加载的类加载器会充当下一个类加载器的父加载器,在双亲委派模型机制下,就能确保安全性。

那么什么是双亲委派模型?比如爷爷、爸爸、你三代单传,你们家族都遗传懒惰基因,每当遇到事情都互相推脱,现在需要一个人去买一包盐,不然今晚的菜就有色无味了,而你第一个被委托去超市买,但由于你的懒惰,你向你爸爸撒了一顿娇,你爸爸受不了你只能答应帮你去,在懒惰的驱使下,你爸爸最后找了一个借口说要赶工作,让你爷爷出去走动走动顺便买一包盐,就这样你爷爷只能乖乖去超市买盐。双亲委派模型就类似这样的机制,类加载器加载类时首先委托给父类加载器加载,除非父类加载器不能加载才自己加载。

这种模型要求除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。假如有一个类要加载进来,一个类加载器并不会马上尝试自己将其加载,而是委派到父类加载器,父类加载器收到后又尝试委派到其父类加载器,以此类推,直到委派到启动类加载器,这样一层一层往上委派。只有当父类加载器反馈自己没法完成这个加载时,子加载器才会尝试自己加载。通过这个机制,保证了Java应用所使用的都是同一个版本的Java核心库的类。同时这个机制也保证了安全性,设想如果Application ClassLoader想要加载一个有破坏性的java.lang.System类,双亲委派模型会一层层向上委派,最终委派给Bootstrap
ClassLoader,而Bootstrap ClassLoader检查到缓存中已经有了这个类,并不会再加载这个有破坏性的System类。

另外,类加载器还拥有全盘负责机制,即当一个ClassLoader加载一个类时,这个类所依赖的、引用的其他所有类都由这个ClassLoader加载,除非在程序中显性地指定另外一个ClassLoader加载。

图2-4-1 类加载器关系

在Java中,我们用完全匹配类名来标识一个类,即用包名和类名。而在JVM中,一个类由完全匹配类名和一个类加载器的实例ID作为唯一标识。即是说同一个虚拟机可以有两个包名、类名都相同的类,只要他们由两个不同类加载器加载。于是当我们在Java中经常说两个类相不相等,必须是针对同一个类加载器加载的前提下才有意义,否则就算是同样的字节代码,由不同类加载器加载,这两个类也不是相等的。这种特征为我们提供了隔离机制,在tomcat服务器中是十分有用的。

了解了JVM的类加载器的各种机制后,看看一个类是怎样被类加载器载入进来的。一个类准备加载,类加载器先判断此类是否已经被加载过(加载过的类会被缓存在内存中),如果缓存中存在此类则直接返回这个类。否则获取父类加载器,如果父类加载器为null,则由Bootstrap ClassLoader载入并返回Class。如果父类加载器不为null,则由父类加载器载入,载入成功就返回Class,载入失败则根据类路径查找class文件,找到就加载此class并返回Class,找不到就抛出ClassNotFoundException异常。

图2-4-2 类加载过程

类加载器属于JVM级别的设计,我们很多时候基本不会跟他打交道,但是假如你想了解整个JAVA体系是如何工作的,假如你要设计开发自己的框架或中间件或一个较庞大的java软件,那么你必须熟悉类加载器的相关机制,在现实的设计中,根据实际情况利用类加载器可以提供类库的隔离及共享,保证你的软件不同级别的逻辑分割程序不会互相影响,提供更好的安全性。

喜欢研究java的同学可以交个朋友,下面是本人的微信号:

java类加载器——ClassLoader的更多相关文章

  1. 深入理解Java类加载器(ClassLoader)

    深入理解Java类加载器(ClassLoader) Java学习记录--委派模型与类加载器 关于Java类加载双亲委派机制的思考(附一道面试题) 真正理解线程上下文类加载器(多案例分析) [jvm解析 ...

  2. 深入理解Java类加载器(ClassLoader) (转)

    转自: http://blog.csdn.net/javazejian/article/details/73413292 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Ja ...

  3. Java 类加载器(ClassLoader)

    类加载器 ClassLoader 什么是类加载器? 通过一个类的全限定名来获取描述此类的二进制字节流这个动作放到Java虚拟机外部去实现, 以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代 ...

  4. 浅析java类加载器ClassLoader

    作为一枚java猿,了解类加载器是有必要的,无论是针对面试还是自我学习. 本文从JDK提供的ClassLoader.委托模型以及如何编写自定义的ClassLoader三方面对ClassLoader做一 ...

  5. 潜水 java类加载器ClassLoader

    类加载器(class loader)用于装载 Java 类到 Java 虚拟机中.一般来说.Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译 ...

  6. Java类加载器ClassLoader总结

    JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中. 2.显式装载, 通过class.forname()等方法,显 ...

  7. Java类加载器(ClassLoader)

    类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Jav ...

  8. Java类加载器(死磕5)

    Java类加载器(  CLassLoader )  死磕5:  自定义一个文件系统classLoader 本小节目录 5.1. 自定义类加载器的基本流程 5.2. 入门案例:自定义文件系统类加载器 5 ...

  9. Java类加载器( 死磕9)

    [正文]Java类加载器(  CLassLoader ) 死磕9:  上下文加载器原理和案例 本小节目录 9.1. 父加载器不能访问子加载器的类 9.2. 一个宠物工厂接口 9.3. 一个宠物工厂管理 ...

随机推荐

  1. 树莓派控制HC-SR04超声波模块测距(新手向+C语言向)

    因为作业要求使用c语言代码,这里先附上一段摘自网上的代码 感谢KalaerSun的c语言代码,摘自https://blog.csdn.net/qq_25247589/article/details/6 ...

  2. [SDOI2017]数字表格

    Description Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师 ...

  3. Chtholly Nota Seniorious

    题目背景 大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg こんなにも.たくさんの幸せをあの人に分けてもらった だから.きっと 今の.私は 谁が何と ...

  4. [hdu4694]Important Sisters

    来自FallDream的博客,未经允许,请勿转载,谢谢. 给定一张图,求每个点到第n个点必须经过的点的编号之和.n<=50000 一道支配树裸题 然后统计答案的时候可以正着推,ans[i]=an ...

  5. 如何彻底删除mysql

    MySQL的卸载确实很让人头疼,很多时候都无法彻底卸载干净,这样会导致我们无法重新安装新的MySQL. 下面介绍,在Windows10系统下,如何彻底删除卸载MySQL... 1>停止MySQL ...

  6. Python 编程规范

    原文传送符:请点击

  7. glusterfs 4.0.1 event模块 分析笔记1

    1. 前言 在C语言i中,存储变量的结构体加上一组函数指针,大概就可以算是一个对象模型了:如果将一组函数指针捆绑为结构体, 后期根据配置或者环境需要绑定到不同实现模块中的一组函数,可以认为是C语言面对 ...

  8. async/await,了解一下?

    上一篇博客我们在现实使用和面试角度讲解了Promise(原文可参考<面向面试题和实际使用谈promise>),但是Promise 的方式虽然解决了 callback hell,但是这种方式 ...

  9. substr和substring的区别

    substr和substring两个都是截取字符串的. 两者有相同点,如果只是写一个参数,两者的作用都是一样的:就是截取字符串当前下标以后直到字符串最后的字符串片段. 例如:`var a=”abcde ...

  10. ref string

    string pics=""; pSub.GetSubjectContent(pddm,ref  pics); public string GetSubjectContent(st ...