##默认的三个类加载器
Java默认是有三个ClassLoader,按层次关系从上到下依次是: - Bootstrap ClassLoader
- Ext ClassLoader
- System ClassLoader Bootstrap ClassLoader是最顶层的ClassLoader,它比较特殊,是用C++编写集成在JVM中的,是JVM启动的时候用来加载一些核心类的,比如:`rt.jar`,`resources.jar`,`charsets.jar`,`jce.jar`等,可以运行下面代码看都有哪些:
```
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
```
其余两个ClassLoader都是继承自`ClassLoader`这个类。Java的类加载采用了一种叫做“双亲委托”的方式(稍后解释),所以除了`Bootstrap ClassLoader`其余的ClassLoader都有一个“父”类加载器, 不是通过继承,而是一种包含的关系。
```
//ClassLoader.java
public abstract class ClassLoader {
...
// The parent class loader for delegation
private ClassLoader parent;
...
```
##“双亲委托”
所谓“双亲委托”就是当加载一个类的时候会先委托给父类加载器去加载,当父类加载器无法加载的时候再尝试自己去加载,所以整个类的加载是“自上而下”的,如果都没有加载到则抛出`ClassNotFoundException`异常。 上面提到Bootstrap ClassLoader是最顶层的类加载器,实际上Ext ClassLoader和System ClassLoader就是一开始被它加载的。 Ext ClassLoader称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有的jar(包括自己手动放进去的jar包)。 System ClassLoader叫做系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件,包括我们平时运行jar包指定cp参数下的jar包。 运行下面的代码可以验证上面内容:
```
ClassLoader loader = Debug.class.getClassLoader();
while(loader != null) {
System.out.println(loader);
loader = loader.getParent();
}
System.out.println(loader);
``` ##“双亲委托”的作用
之所以采用“双亲委托”这种方式主要是为了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如String,同时也避免了重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类,如果相互转型的话会抛`java.lang.ClassCaseException`. ##自定义类加载器
除了上面说的三种默认的类加载器,用户可以通过继承`ClassLoader`类来创建自定义的类加载器,之所以需要自定义类加载器是因为有时候我们需要通过一些特殊的途径创建类,比如网络。 至于自定义类加载器是如何发挥作用的,`ClassLoader`类的loadClass方法已经把算法定义了:
```
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
``` >1. Invoke `findLoadedClass(String)` to check if the class has already been loaded. >2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead. >3. Invoke the `findClass(String)` method to find the class. 看上面的Javadoc可以知道,自定义的类加载器只要重载`findClass`就好了。
##Context ClassLoader
首先Java中ClassLoader就上面提到的四种,`Bootstrap ClassLoader`,`Ext ClassLoader`,`System ClassLoader`以及用户自定义的,所以`Context ClassLoader`并不是一种新的类加载器,肯定是这四种的一种。 首先关于类的加载补充一点就是如果类A是被一个加载器加载的,那么类A中引用的B也是由这个加载器加载的(如果B还没有被加载的话),通常情况下就是类B必须在类A的classpath下。 但是考虑多线程环境下不同的对象可能是由不同的ClassLoader加载的,那么当一个由ClassLoaderC加载的对象A从一个线程被传到另一个线程ThreadB中,而ThreadB是由ClassLoaderD加载的,这时候如果A想获取除了自己的classpath以外的资源的话,它就可以通过`Thread.currentThread().getContextClassLoader()`来获取线程上下文的ClassLoader了,一般就是ClassLoaderD了,可以通过`Thread.currentThread().setContextClassLoader(ClassLoader)`来显示的设置。 ##为什么要有Context ClassLoader
之所以有Context ClassLoader是因为Java的这种“双亲委托”机制是有局限性的: - 举网上的一个例子: > JNDI为例,JNDI的类是由bootstrap ClassLoader从rt.jar中间载入的,但是JNDI具体的核心驱动是由正式的实现提供的,并且通常会处于-cp参数之下(注:也就是默认的System ClassLoader管理),这就要求bootstartp ClassLoader去载入只有SystemClassLoader可见的类,正常的逻辑就没办法处理。怎么办呢?parent可以通过获得当前调用Thread的方法获得调用线程的>Context ClassLoder 来载入类。 - 我上面提到的加载资源的例子。 `Contex ClassLoader`提供了一个突破这种机制的后门。 Context ClassLoader一般在一些框架代码中用的比较多,平时写代码的时候用类的ClassLoader就可以了。 ##参考链接
[http://stackoverflow.com/questions/1771679/difference-between-threads-context-class-loader-and-normal-classloader][1] [1]: http://stackoverflow.com/questions/1771679/difference-between-threads-context-class-loader-and-normal-classloader

Java基础—ClassLoader的理解的更多相关文章

  1. Java基础—ClassLoader的理解(转)

    默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是: Bootstrap ClassLoader Ext ClassLoader System ClassLoad ...

  2. java的classLoader原理理解和分析

    java的classLoader原理理解和分析 学习了:http://blog.csdn.net/tangkund3218/article/details/50088249 ClassNotFound ...

  3. Java 基础:认识&理解关键字 native 实战篇

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 泥瓦匠初次遇见 navicat 是在 java.lang.Object 源码中的一个hashCode方 ...

  4. Java基础之深入理解Class对象与反射机制

    深入理解Class对象 RRIT及Class对象的概念 RRIT(Run-Time Type Identification)运行时类型识别.在<Thinking in Java>一书第十四 ...

  5. Java基础系列-深入理解==和equals的区别(一)

    一.前言 说到==和equals的问题,面试的时候可能经常被问题到,有时候如果你真的没有搞清楚里边的原因,被面试官一顿绕就懵了,所以今天我们也来彻底了解一下这个知识点. 二.==和equals的作用 ...

  6. java基础强化——深入理解反射

    目录 1.从Spring容器的核心谈起 2. 反射技术初探 2.1 什么是反射技术 2.2 类结构信息和java对象的映射 3 Class对象的获取及需要注意的地方 4. 运行时反射获取类的结构信息 ...

  7. java基础强化——深入理解java注解(附简单ORM功能实现)

    目录 1.什么是注解 2. 注解的结构以及如何在运行时读取注解 2.1 注解的组成 2.2 注解的类层级结构 2.3 如何在运行时获得注解信息 3.几种元注解介绍 3.1 @Retention 3.2 ...

  8. Java基础-四大特性理解(抽象、封装、继承、多态)

    抽象: 象就是有点模糊的意思,还没确定好的意思. 就比方要定义一个方法和类.但还没确定怎么去实现它的具体一点的子方法,那我就可以用抽象类或接口.具体怎么用,要做什么,我不用关心,由使用的人自己去定义去 ...

  9. [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!

    java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方. synchronized关键字涉及到锁的概念, 在java中,synchronized ...

随机推荐

  1. 蓝牙技术BlueTooth

    转载网址:http://blog.csdn.net/dxdxsmy/article/details/7790568 蓝牙核心架构概念的理解请参考上面的网址.

  2. iOS开发UI篇—popoverController简单介绍(ipad)

    一.简单介绍 1.什么是UIPopoverController 是iPad开发中常见的一种控制器(在iPhone上不允许使用) 跟其他控制器不一样的是,它直接继承自NSObject,并非继承自UIVi ...

  3. 使用网易云音乐,丢掉QQ音乐吧

    我是一个听音乐的重度用户,基本上每天大约有三分之一的时间里我在使用网易云音乐去听音乐.包括工作写代码的时候,跑步的时候,去上班的途中我都去听.首先需要声明的是,在这里我不是故意的去抹黑其他的音乐产品, ...

  4. 【微收藏】来自Twitter的自动文字补齐jQuery插件 - Typeahead.js

    没图没逼格 事发有因 该插件可以结合本地数据进行一些操作.推荐关注一下H5的几种数据存储的方式(localstorage与sessionstorage.IndexedDB.离线缓存manifest文件 ...

  5. Git.Framework 框架随手记--ORM项目工程

    前面已经简单介绍过了该框架(不一定是框架),本文开始重点记录其使用过程.可能记录的内容不是太详尽,框架也可能非常烂,但是里面的代码句句是实战项目所得.本文非教唆之类的文章,也非批判之类的文章,更不是炫 ...

  6. angular的splitter案例学习

    angular的splitter案例学习,都有注释了,作为自己的备忘. <!DOCTYPE html> <html ng-app="APP"> <he ...

  7. GDI+中发生一般性错误的解决办法(转帖)

    今天在开发.net引用程序中,需要System.Drawing.Image.Save 创建图片,debug的时候程序一切正常,可是发布到IIS后缺提示出现“GDI+中发生一般性错误”的异常.于是开始“ ...

  8. 团队作业--Beta版本冲刺

    项目冲刺随笔 第一天 第二天 第三天 第四天 第五天 第六天 第七天

  9. iOS边练边学--父子控制器之自定义控制器的切换

    一.如图所示的界面,按钮One.Two.Three分别对应三个控制器的view,点击实现切换.个人感觉父子控制器的重点在于,控制器的view们之间建立了父子关系,控制器不建立的话,发生在view上面的 ...

  10. text-align:justify_内容居中对齐

    一直发现text-align : justify这个对齐方式不好使,都不知道为什么么么哒: 因为两端对齐的这个行的结束要一个有空字符串或者别的不可见的字符,用户代理会把这个行的最后几个字符往右边拉,实 ...