Java基础—ClassLoader的理解
##默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是:- Bootstrap ClassLoader- Ext ClassLoader- System ClassLoaderBootstrap 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 delegationprivate 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 loadedClass 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的理解相关推荐
- Java基础-我所理解的泛型
Java基础-我所理解的泛型 引用 [java]泛型中,? extends T 与 ? super T 的区别.看法_winrh的博客-CSDN博客_泛型 extends 前言 Java基础系列,我所 ...
- java基础(十) 深入理解数组类型
戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 1. 数组类简介 在java中,数组也是一种引用类型,即是一种类. ...
- java基础篇 - HashMap 理解Hash碰撞
HashMap是大家都在用,面试的时候也经常会被考的考点,在这篇文章中说下HashMap的hash碰撞和减轻碰撞的优化. 1.什么是hash碰撞 在解释Hash碰撞之前先说一下hashmap的存储结构 ...
- java基础篇之理解synchronized的用法
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this ...
- java基础(多态的理解与应用)
1:多态概述 代码中的多态:父类引用指向子类对象.Animal ani = new Dog(); 狗是动物,这就是多态. 父类名称 变量名 = new 子类名称(); 接口名称 对象名 = new 实 ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- 你所需要的java基础篇和提升篇大总结
好好学java 致力于java知识分享 关注 精彩内容 你所需要的java全套视频教程 你所需要的java电子图书 你所需要的大数据视频教程 你所需要的java练习项目 如 / 诗 近半个月,每天一篇 ...
- 你所需要的java基础提升篇大总结
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- 夯实Java基础系列9:深入理解Class类和Object类
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
最新文章
- html5 settimeout,计时器setTimeout()
- vue 返回滚动条顶部组件_vue中回到顶部
- Xcode多Target设置
- vue-cli 搭建vue项目
- RBAC(基于角色的权限访问控制)
- 阿里云服务器一分价钱一分货,切记!
- 史上最全AI开源项目集结,近万篇附代码的论文分门别类整理好
- Kubernetes学习之路(26)之kubeasz+ansible部署集群
- declare-styleable中format详解
- 北京长途汽车站一览表
- 私密智能搜题小助手,支持智能图片识别和智能复制,支持多接口
- 串口硬盘如何应用于并口硬盘计算机,串口硬盘和并口硬盘的区别 并口硬盘怎么改串口硬盘【详解】...
- 推荐8个不错的视频自动加字幕工具
- 九连环问题c语言程序,九连环游戏的算法源代码
- 全国计算机等级一级(选择题的)的练习,附加答案
- 计算机的内存的材料是什么,内存条到底是干啥的?手把手的告诉你
- 侏罗纪怪兽世界怎么登陆服务器未响应,全金属怪物一直登入不进去怎么办
- 高薪背后的“难言之隐”,热门职业最为真实的健康观察报告
- 太可怕,有码变高清!AI 一秒还原马赛克?
- win10双显示器 鼠标移动总感觉到另一屏困难
热门文章
- 对抗 Google优势 微软考虑收购雅虎
- Mac下使用crontab来实现定时任务
- Arch安装zsh以及通过 Oh-My-ZSH! 开源项目的配置
- php libev pthreads,libuv 与 libev 的对比
- python的这几个小功能,你都会用了吗?
- 电脑记事本_办公便签记事本
- python 返回字符串长度,当使用特殊字符时,Python返回错误的字符串长度
- spring boot2 修改默认json解析器Jackson为fastjson
- SPI通信协议:单片机spi通信接口什么意思,spi接口干什么用的?
- java对象的访问定位_2、JVM-Java对象的创建、对象结构、对象访问定位-Go语言中文社区...