类加载器的功能:通过一个类的全限定名来获取描述此类的二进制字节流的过程
java的类加载器大致可以分为两类,一类是系统提供的,一类是由应用开发人员编写的。系统提供的类加载器有以下三种:
引导类加载器(bootstrap class loader):用来加载 Java 的核心库(rt.jar),是用原生代码来实现的,并不继承自 java.lang.ClassLoader
扩展类加载器(extensions class loader):用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
应用(系统)类加载器(Application class loader):根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。
另外还有开发人员自定义的Class loader。
系统在进行类加载时,会使用parent delegation原则。
parent delegation原则的工作过程:如果一个类加载器需要加载某个类时,它不会自己去尝试加载这个类,而是新该加载请求委托给其父类加载器去完成。同样父类加载器也会将该请求委托给其父类,直到顶层的Bootstrap Class Loader,引导类加载器根据请求,尝试加载类文件。如果加载类文件失败,则会反向由其子加载器去尝试加载,直到能加载成功的子加载器为止。简化后的顺序如下:
自定义类加载器->应用类加载器->扩展类加载器->引导类加载器
parent delegation的优势是什么?
通过parent delegation的方式,可以保证,java程序的稳定器,java判断是否是相同类,会要求两个类必须由同一类加载器加载。如果没有parent delegation的原则,对于同一个类,可能经由多个类加载器去加载。而每个类加载器加载到的类,被虚拟机认定为不同类,可想而知,这样会有多少操作和方法都不能执行。
parent delegation的实现代码?
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;
}
如以上代码所示,parent delegation的实现非常简单,首先findLoadedClass(调用native方法)查找类是否已经被加载,如果类未被加载,则通过parent. loadClass(name, false);加载类,只有父加载器未加载成功,才会通过当前类加载器去加载。
特例-线程上下文类加载器
对于大多数的类加载都可以通过parent delegation的方式去现实,但有没有特例情况呢?如:jndi接口位于rt.jar包中,rt属于java核心类,其加载都通过bootstrap class loader完成。但jndi的实现,是由外部提供,不属于rt中。非rt包中的类,对于bootstrap class loader是不可见的,是无法加载的。那在加载jndi接口的同时,怎么样去加载jndi的实现呢?这时,可以通过线程上下文类加载器去实现,线程上下文类加载器并不是一个真正的类加载器,它是相对当前类加载器来说的。
     把线程上下文类加载器定义成一种方式更合适,线程上下文类加载器其实就是一种可以在父类加载器的环境下,调用子类加载器的方式。表面上看起来似乎与parent delegation有冲突,其实不然,父类还是无法直接调用子类加载器的,能调用子类加载器的,只是在当前类加载器是父类加载器的线程环境,通过当前线程的getContextClassLoader()方法,去获取其它类加载器。示例如下:
 package com.csair.soc.thread;

 import java.io.IOException;
import java.io.InputStream; public class MyClassLoader extends ClassLoader{
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
String fileName = name.substring(name.lastIndexOf("." ) + 1)
+ ".class";
InputStream is = this.getClass().getResourceAsStream(fileName);
if (is == null) {
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b. length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
}
 package com.csair.soc.thread;

 public class ThreadContextTest {
public static void main(String[] args) throws ClassNotFoundException {
ThreadTest tt = new ThreadTest();
//设置线程的上下文类加载器
tt.setContextClassLoader( new com.csair.soc.thread.MyClassLoader());
tt.start();
}
public static class ThreadTest extends Thread{
public void run() {
try {
System. out.println( "线程上下文类加载器:" + getContextClassLoader());
System. out.println( "当前类加载器:" +this.getClass().getClassLoader());
Class<?> class1 = getContextClassLoader().loadClass("com.csair.soc.thread.ThreadContextTest" );
System. out.println( "加载class的类加载器:" +class1.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
输出结果:
线程上下文类加载器:com.csair.soc.thread.MyClassLoader@af8358
当前类加载器:sun.misc.Launcher$AppClassLoader@ad3ba4
加载class的类加载器:com.csair.soc.thread.MyClassLoader@af8358
 
通过线程上下文类加载器就能解决jndi的加载问题了,在当前类加载器为bootstrap class loader的线程环境下,线程通过getContextClassLoader()方法,获取提前设置的线程类加载器(Application class loader),去加载jndi的实现类。


classLoader怎么样持有实体类?为什么classLoader卸载后,实体类也跟着被卸载?
classloader会有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。对于class的卸载,Sun公司的原话是这么说的:"class or interfacemay be unloaded if and only if its class loader is unreachable. Classesloaded by the bootstrap loader may not be unloaded.当某个类的加载器被gc回收之后,该类才能被卸载
Class.forname()和ClassLoader.loadClass有什么区别,首次new XXX(),是怎么加载class的?
java提供两个方法来加载类
1、隐匿加载,如new XXX()方式来隐式加载class
2、显示加载,java.lang.Class里的forName()方法,java.lang.ClassLoader里的loadClass()
forName实际上调用native方法,forName0(className, true , ClassLoader.getCallerClassLoader ());

通过当前类加载器,来加载className。第二个参数为true表示装载类的时候是否初始化该类,即调用类的静态块的语句及初始化静态成员变量。

而使用loadClass加载类时,默认是不初始化该类的。

类加载器符合parent delegation的原则,那自定义的类加载器,为什么能加载class?
自定义类加载器,可以重写loadClass不遵守parent delegation原则。另外,有些类文件对于系统的类加载器不可见,或者说系统的类加载器找不到类文件,此时,自定义类加载器通过自定义的findClass方法去找到类文件。

JAVA类加载器概念与线程类加载器的更多相关文章

  1. 深入理解Java类加载器(二):线程上下文类加载器

    摘要: 博文<深入理解Java类加载器(一):Java类加载原理解析>提到的类加载器的双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器的实现方式.在Java ...

  2. Java中的类加载器以及Tomcat的类加载机制

    在加载阶段,虚拟机需要完成以下三件事情: 1.通过一个类的全限定名来获取其定义的二进制字节流. 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构. 3.在Java堆中生成一个代表这个类 ...

  3. 深度分析:Java虚拟机类加载机制、过程与类加载器

    虚拟机类加载机制是把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型. ​ 需要注意的是 Java 语言与其他编译时需要进 ...

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

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

  5. java类加载器学习2——自定义类加载器和父类委托机制带来的问题

    一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...

  6. Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用2

    1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名 ...

  7. Java类加载机制及自定义加载器

    转载:https://www.cnblogs.com/gdpuzxs/p/7044963.html Java类加载机制及自定义加载器 一:ClassLoader类加载器,主要的作用是将class文件加 ...

  8. Java 类加载器解析及常见类加载问题

    Java 类加载器解析及常见类加载问题 java.lang.ClassLoader 每个类加载器本身也是个对象--一个继承 java.lang.ClassLoader 的实例.每个类被其中一个实例加载 ...

  9. java中定义的四种类加载器

    1,Bootstrap ClassLoader   启动类加载器2,ExtClassLoader   扩展类加载器3,AppClassLoader   系统类加载器4,ClassLoader   类加 ...

随机推荐

  1. Visual Studio 2012连接TFS2010登录不了

    一直用VS2012+TFS2010开发项目, 最近几天忽然很不正常, 在VS中会频繁要求输入TFS的账号密码, 经常要输入很多遍才可以正常连接签入签出. 这几天更甚, 基本上直接连接不了了. 网上找到 ...

  2. A4纸的象素分辨率计算[转]

    在公制长度单位与屏幕分辨率进行换算时,必须用到一个DPI(Dots Per Inch)指标.在Windows系统的网页打印中默认采用的是96dpi,Mac系统中默认的是72dpi. A4纸张的尺寸是2 ...

  3. [Android 新特性] Android 4.3新功能(正式发布前)

    腾讯数码讯(编译:徐萧梓丞)虽然谷歌公司目前尚未正式对外发布最新的Android 4.3果冻豆操作系统,但是在上周我们已经看到了关于三星正 在为原生版Galaxy S4进行Android 4.3系统进 ...

  4. 14.ThreadLocal

    ThreadLocal     1.线程局部变量,是一种多线程并发访问变量的解决方案,与同步技术 synchronize 加锁的方式不同,threadlocal完全不提供锁,而使用        空间 ...

  5. Android系统信息获取

    在Android中可以通过android.os.Build这个类和System.getProperty(“xxx”);来获取设备信息,下面列举的常见设备信息摘自Android群英传 Build.BOA ...

  6. IE6BUG汇总篇(不断更新)

    1.IE6双倍边距bug 当页面内有多个连续浮动时,如本页的图标列表是采用左浮动,此时设置li的左侧margin值时,在最左侧呈现双倍情况.如外边距设置为10px, 而左侧则呈现出20px,解决它的方 ...

  7. cocos2d-x游戏开发 跑酷(八) 对象管理 碰撞检測

    对象管理类的原理是这种: ObjectManager类是一个单例类,全局仅仅有一个对象实例存在.初始化的时候创建两个数组CCArray来保存金币和岩石.为什么要保存,由于在地图重载的时候.要销毁看不见 ...

  8. Linux下QTCreator代码自动补全(是真的自动补全,不是手动触发)

    在使用Windows下的QTCreator的时候,像visual studio一样代码自动补全十分方便,而在Linux下,QTCreator似乎不能做到. 网上有些说是可以设置成手动补全,今天试了一下 ...

  9. 网络电台-SHOUTcast

    网络电台种类 目前的网络电台网站一般是基于以下三种协议的: mms.rtsp.http 其中mms是微软公司提出的网络流媒体协议,通常采用wma格式的文件,Android现在还不支持这种协议,也不支持 ...

  10. http协议中content-length 以及chunked编码分析

    转载请注明出处 http://blog.csdn.net/yankai0219/article/details/8269922 0.序 1.http/1.1协议中与chunked编码的相关字段 1)E ...