类加载器和双亲委派机制

每个开发人员对java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,这个异常背后涉及到的是Java技术体系中的类加载机制. 本文简述了JVM三种预定义类加载器,即启动类加载器,扩展类加载器和系统类加载器,并介绍和分析它们之间的关系和类加载所采用的双亲委派机制,给出并分析了与Java类加载原来相关的若干问题.


版权声明:

本文作者:书呆子Rico
作者博客地址:http://blog.csdn.net/justloveyou_/


一、引子

每个开发人员对java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,其实,这个异常背后涉及到的是Java技术体系中的类加载。Java类加载机制虽然和大部分开发人员直接打交道的机会不多,但是对其机理的理解有助于排查程序出现的类加载失败等技术问题,对理解Java虚拟机的连接模型和Java语言的动态性都有很大的帮助


二、Java虚拟机类加载器结构简述
1.JVM三种预定义类型类加载器
当JVM启动的时候,Java开始使用如下三种类型的类加载器

启动类加载器Bootstrap:启动类加载器是用本地代码实现的类加载器,它负责将JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中. 由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用.具体可由启动类加载器加载到的路径可通过System.getProperty(“sun.boot.class.path”)查看。

扩展类加载器Extension扩展类加载器是由Sun的ExtClassLoader实现的,它负责将JAVA_HOME/lib/ext或者由系统变量-DJAVA.ext.dir指定位置中的类库加载到内存中.开发者可以直接使用标准扩展类加载器,具体可由扩展类加载器加载到的路径可通过System.getProperty(“java.ext.dirs”)查看。

系统类加载器System:系统类加载器是由Sun的AppClassLoader实现的,它负责将用户类路径(ava -classpath或-Djava.class.path变量所指的目录,即当前类所在路径及其引用的第三方类库的路径,如第四节中的问题6所述)下的类库加载到内存中.开发者可以直接使用系统类加载器,具体可由系统类加载器加载到的路径可通过System.getProperty(“java.class.path”)查看。


类加载双亲委派机制介绍和分析
JVM在加载类时候默认采用的是双亲委派机制. 通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务托付给父类加载器,依次递归(本质上就是loadClass函数的递归调用),因此所有的加载请求最终都应该传送到顶层的启动类加载器中.如果父类加载器可以完成这个类加载请求,就成功返回;只有当父类加载器无法完成此加载请求时候,子加载器才会尝试自己区加载.事实上,大多数情况下,越基础的类由越上层的类加载器进行加载,因为这些基础类之所以称为"基础",是因为它们总是作为被用户代码调用的API.关于虚拟机默认的双亲委派机制,我们可以从系统类加载器和扩展类加载器为例做简单分析.
在这里插入图片描述在这里插入图片描述
上面两张图分别是扩展类加载器继承层次图和系统类加载器继承层次图.通过这两张图我们可以看出,扩展类加载器和系统类加载器均是继承 java.lang.ClassLoader抽象类.
关于抽象类 java.lang.ClassLoader中有几个最重要的方法

//加载指定名称(包括包名)的二进制类型,供用户调用的接口
public Class<?> loadClass(String name) throws ClassNotFoundException{ … }
//加载指定名称(包括包名)的二进制类型,同时指定是否解析(但是这里的resolve参数不一定真正能达到解析的效果),供继承用
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ … }
//findClass方法一般被loadClass方法调用去加载指定名称类,供继承用
protected Class<?> findClass(String name) throws ClassNotFoundException { … }
//定义类型,一般在findClass方法中读取到对应字节码后调用,final的,不能被继承
//这也从侧面说明:JVM已经实现了对应的具体功能,解析对应的字节码,产生对应的内部数据结构放置到方法区,所以无需覆写,直接调用就可以了)
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError{ … }

通过进一步分析标准扩展类加载器和系统类加载器的代码以及其公共父类的代码可以看出,都没有覆写ava.lang.ClassLoader中默认的加载委派规则 — loadClass(…)方法。既然这样,我们就可以从java.lang.ClassLoader中的loadClass(String name)方法的代码中分析出虚拟机默认采用的双亲委派机制到底是什么模样:

public Class<?> loadClass(String name) throws ClassNotFoundException {
     
    return
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值