分享

类加载器ClassLoader的详解

 gaoshenmu 2016-09-11
java文件在解释成class文件之后,需要对里面的类进行初始化,初始化的过程包括加载、连接、装入三个过程,在加载的过程中会对类里面的静态变量进行一个初始化。下面详细介绍下ClassLoader:
1、类的加载、连接和初始化
类初始化通常包括加载、连接、初始化三个步骤。
(1)进程的结束
每当运行一个java程序时,将会启动一个java虚拟机进程,不管程序多么复杂,有多少线程,都在这个java虚拟机进程里。以下四种情况会使得该进程被终止——
程序运行到最后正常结束; 程序里遭遇了System.exit(),或者是Runtime.getRunTime().exit()代码;程序执行中遇到了未捕获的异常或者错误; java所在平台强制结束了JVM进程;
当该进程结束,那么该进程在内存中的状态将会丢失,包括静态变量的值。
(2)类的加载
类的加载是指将类的class文件读入内存,并为之创建一个java.lang.class对象。
(3)类的连接
类的连接负责把类的二进制数据合并到JRE中,分为三个阶段——
验证:检验被加载的类是否有正确的内部结构; 准备:负责为类的静态Field分配内存,并设置默认初始值;解析:将类的二进制数据中的符号应用替换成直接引用。
(4)类的初始化
类的初始化,主要就是对静态Field进行初始化。
2、类加载器
(1)类加载器简介
类加载器负责加载所有的类,系统为所有载入内存里的类都会生成一个java.lang.class对象;
同一个类只会被加载一次,在JVM中每一个不同的类都会有一个不同的类加载器负责。
类加载器在不包括用户自定义的加载器的情况下包括三层:
Bootstrap Classloader根加载器; ExtensionClassloader扩展类加载器; SystemClassLoader系统类加载器;
①根加载器,又称为引导或者原始加载器,负责加载java的核心类;
②扩展类加载器,负责加载JRE的扩展目录中JAR包的类;
③系统类加载器,又称为应用加载器,
负责JVM启动时加载来自java命令的-classpath或者CLASSPATH环境变量所指定的JAR包和类路径。一般是程序运行的当前路径。所以其称为应用类加载器。
三个类加载器的顺序是:
bootstrap classloader
|
extension classloader
|
system classloader
如果有用户自定义的类加载器,那么在系统加载器后,将会执行用户类加载器。
(2)自定义类加载器
如果我们需要在启动类加载时作一些特定需求的行为,那么就需要自定义类加载器了。
自定义ClassLoader需要继承ClassLoader抽象类,重写findClass方法,这个方法定义了ClassLoader查找class的方式。
主要可以扩展的方法有:
findClass 定义查找Class的方式
defineClass 将类文件字节码加载为jvm中的class
findResource 定义查找资源的方式
(3)类加载机制
JVM的类加载机制有以下三种:
全盘负责:所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入。
父类委托:所谓父类委托,就是先让父类加载器先尝试加载该Class,当父类无法加载的时候,才是尝试从自己的类路径中去加载。JVM的ClassLoader采用的是树形结构,除了BootstrapClassLoader以外,每个ClassLoader都会有一个parentClassLoader,即父类加载器,用户自定义的ClassLoader默认的parendClassLoader是SystemClassLoader,当然你可以自己指定需要用哪一个ClassLoader的实例
缓存机制:所谓缓存机制就是保证所有加载过的类都会被缓存,当程序中需要某个类时,会先从缓存区中搜查该类,当缓存区不存在该类对象时,系统才会读取该类的二进制文件。
4、一些重要的方法
(1)loadClass方法
ClassLoader.loadClass()是ClassLoader的入口点。该方法的定义如下:
Class loadClass(String name,boolean resolve);
name是加载的类的名称,resolve是告诉方法是不中需要解析类PS:并不是所有的类都需要解析,如果JVM只想知道这个类是否存在或找出该类的超类,那么就不需要解析该类
(2)defineClass方法
defineClass方法接受由原始字节组成的数组,并把它转换成Class的对象。原始数组包含如从文件系统或网络装入的数据。defineClass管理JVM的许多复杂的实现层面——它把字节码分析成运行时数据结构、校验有效性等,因为defineClass方法被标记成final的,所以不能覆盖它。
(3)findSytemClass方法
findSystemClass方法就是查找本的类Class文件,然后装入
(4)resolveClass方法
我们在调用编写自己的loadClass方法的时候可以调用resolveClass方法来获得resolve参数
(5)findLoadedClass方法
在调用loadClass方法之前可以调用改方法来查看地ClassLoader是否已经装入了这个类,这样可以避免重新装入这个类
(6)findClass方法
在loadClass默认实现调用这个新方法。findClass的用途包含classLoader的所有特殊代码,而无须复制其他代码
(7)getSystemClassLoader方法
在如果覆盖findClass或loadClass,getSystemClassLoader能以实际的ClassLoader对象访问系统ClassLoader(而不是固定地从findSystemClass调用它)。为了将类请求委托给父类ClassLoader,这个新方法允许ClassLoader获取它的父类ClassLoader.当使用特殊方法,定制的ClassLoader不能找到类时,可以使用这种方法。
父类ClassLoader被定义成创建该ClassLoader所包含代码的对象的ClassLoader.
(8)forName方法
在Class类中有一个静态方法forName,这个方法和ClassLoader中的loaderClass方法的目的是一样的,都是用来加载Class的,但是两者在作用上却有所区别:
loadClass加载实际上就是加载的时候并不对该类进行解释,因此不会初始化该类。而Class类的forName方法则相反,使用forName加载的时候就会将Class进行解释和初始化

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多