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. 素数密度_NOI导刊2011提高(04)

    题目描述 给定区间[L, R](L <= R <= 2147483647,R-L <= 1000000),请计算区间中素数的个数. 输入 两个数 L 和 R. 输出 一行,区间中素数 ...

  2. 【NOIP模拟赛】总结

    题目描述 输入 第一行是5个正整数,n,m,k,S,T,分别代表无向图点数,边数,蝙蝠的数量,二小姐所在起点的编号,目标点的编号. 第二行是k个正整数,分别代表大小姐每个蝙蝠所在的起点的编号.接下来有 ...

  3. hdu 5667 BestCoder Round #80 矩阵快速幂

    Sequence  Accepts: 59  Submissions: 650  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 65536 ...

  4. POJ 3233 (矩阵)

    题意:对于矩阵A,求A^1 + ...... + A^k 按照矩阵十大经典题的思路大致做了下. 在k为奇数时:  A^( k / 2+1)+ 1) * (A^1 + ....... A^(k/2)) ...

  5. [UOJ UNR#2 黎明前的巧克力]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 很奇妙的一道题 首先不难发现一个暴力做法,就是f[i]表示异或和为i的答案数,每次FWT上一个F数组,其中F[0]=1,F[ai]=2 ...

  6. SAM维护的在线LCS

    题目大意: 给定两个字符串,存在三种操作,分别是在a,b串末尾加一个字符串,和询问两串的LCS 题解: Get新套路:把两串建在同一SAM上,将重合的位置合并为同一节点,再加个标记数组,如果两者的LC ...

  7. [BZOJ]3672 购票(Noi2014)

    革命尚未成功,同志还需努力. Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ ...

  8. NTT+多项式求逆+多项式开方(BZOJ3625)

    定义多项式$h(x)$的每一项系数$h_i$,为i在c[1]~c[n]中的出现次数. 定义多项式$f(x)$的每一项系数$f_i$,为权值为i的方案数. 通过简单的分析我们可以发现:$f(x)=\fr ...

  9. 凸包(BZOJ1069)

    顶点一定在凸包上,我们枚举对角线,观察到固定一个点后,随着另一个点的增加,剩下两个点的最优位置一定是单调的,于是就得到了一个优秀的O(n^2)做法. #include <cstdio> # ...

  10. ajax中基本参数应用

    $(function () { $("#verificationCodeBtn").click(function () { $("#verificationCodeIma ...