JVM是如何知道java.lang包中的类的?JVM又是如何知道我们应用中的类的?我们的应用中明明是有某个类, 但是JVM却抛出ClassNotFoundException,这是为什么?XxxImpl类已经实现了接口Xxx,但是却抛出XxxImpl does not extend from Xxx,这是为什么?使用类型转换时,可能会抛出 aa.bb.cc.XXX can not cast to aa.bb.cc,这又是为什么?等等诸多看似诡异情况,其实都是因为ClassLoader。

了解反射的人都知道每一个类都有一个Class对象与之对应,那么这个Class对象又是哪来的呢?

如果要了解Class的基本知识,可以参考:

http://blog.csdn.net/irelandken/article/details/7048817

http://tyrion.iteye.com/blog/1958814

http://www.blogjava.net/lihuaxajh/articles/94371.html

http://www.javaworld.com/article/2077332/core-java/get-a-load-of-that-name.html

http://www.javaworld.com/article/2075796/java-platform/java-101--class-and-object-initialization.html

我对ClassLoader的理解

下面是我看了这些博客、文章后,并自定义了一个ClassLoader进行测试后的理解:

1)ClassLoader加载一个类时,不会加载类中所有的类,而是在运行时根据要使用的类动态加载的,即按需加载。

2)ClassLoader加载一个类时,也会加载其父类(包括接口)

3)当前类A在运行时,类中要使用的其它的类(B,C,D类等),默认是由当前类A的加载器来加载的。

4)类型强制转换时,先判定是不是同一个类加载器,如果不是,就不能进行转换。一个对象A但往由BootstrapCLassLoader加载的类(A的父类或者接口)转换时,好像不遵循这个过程。

5)Thread#contextClassLoader可以用于在切换类加载器。

6)默认情况下,线程的上下文加载器采用的与父线程的上下文加载器是同一个。

7)Class.forName(“xxx”)、Xxx.class 的加载器,使用的都是当前类的类加载器。

下面是自定义类加载器

代码清单:

下面就对这些类做一个简单的说明:

StringUtil.java

StringUtil中只有两个方法,用于判断字符串空值。写这个类实在是没有必要,但是在测试中也可以看到效果的。

DebugUtil.java

只是为了打出一些信息。

Person.java

这是一个典型的Java Bean,没有什么可说的。

ClassLoaderTestRunner.java

这是业务类。从代码上看也是很简单的,只是加载了Person类,创建一个Person对象,输出一些信息。

这个类 既可以使用系统默认的类加载器加载测试(main方法),也可以使用自定义的类加载器来测试。

自定义ClassLoader

目前常用的加载机制有两种:委托加载机制、子类优先加载

1)委托加载机制loadClass()的流程:

(1) 判断是否已经加载这个类

(2) 如果没有加载,当前类加载器的父加载器加载,即执行loadClass()方法。

(3) 如果当前类加载器的所有父加载器都没有加载到就让当前加载器调用 findClass()加载。

2)子类优先加载器的流程:

(1) 判断是否已经加载这个类

(2) 当前类加载器直接加载类

(3) 加载不到才走父类加载流程。

JDK中默认的加载方式是1),也就是委托加载机制。

自定义类加载器,一般会重写loadClass、findClass。

delegate字段是用于指定是否使用默认的委托加载机制。

这是自定义的加载类的方法。流程是:

1)判断该加载器是否已经加载了这个类,为了避免重复的加载。

2)如果delegate=true,委托加载,就使用默认的加载方式。

3)如果delegate=false, 排除受保护的类,然后使用下面的自定义的findClass来加载类。上述过程如果出现了异常,仍然会使用默认的加载方法。

findClass是根据类名加载并定义一个Class对象。这个方法写的很粗糙,只是为了测试ClassLoader。

接下来就可以使用ClassLoaderTest.java来测试了:

关于这个测试的简单说明:

1)这个测试中的相关类,如String, UrlClassLoader, ClassLoader,Object, Thread,Runnable,Exception等都是由默认的系统加载器(SystemClassLoader)或者其父类(ExtClassLoader、BootstrapClassLoader)来加载的。当前这个运行时,这个类(ClassLoaderTest)的加载器是SystemClassLoader。

2)加载ClassLoaderTestRunner类时,使用的自定义的类加载器(也就是SystemClassLoader的子加载器)。加载ClassLoaderTestRunner类时,还会加载其父类,也就是Object类和Runable接口。

3)这个测试执行的过程:

(1) 创建一个自定义加载器实例,指定其父加载器为系统加载器。

(2) 加载类ClassLoaderTestRunner。

(3) 启动一个线程执行相关任务。

4)根据上述所说,如果将Object task = myAppClassLoader .loadClass( classFullName) . newInstance();

改为:

ClassLoaderRunner task= (ClassLoaderRunner) myAppClassLoader. loadClass( classFullName ) . newInstance();就会出错。

ClassLoaderRunner 是系统加载器加载的,myAppClassLoader是一个自定义加载器。所以两者不能进行类型的转换。

如果直接在这个类中使用自定义类加载器来加载Person类,也会出现错误。

如果有兴趣的话,可以根据我上面总结的内容,已经我的这个测试,自己分析一下子线程t执行过程中,哪些类是被自定义的类加载器加载的,哪些类是被系统加载器加载的,上述task执行的结果是什么?

如果有不理解的也可以参考:

参考

http://blog.csdn.net/irelandken/article/details/7048817

http://tyrion.iteye.com/blog/1958814

http://www.blogjava.net/lihuaxajh/articles/94371.html

http://www.javaworld.com/article/2077332/core-java/get-a-load-of-that-name.html

http://www.javaworld.com/article/2075796/java-platform/java-101--class-and-object-initialization.html

Java Se:自定义ClassLoader的更多相关文章

  1. JAVA 利用JNI加密class文件/自定义ClassLoader 类

    利用 JNI 对bytecode 加密.不影响java程序员的正常开发.09年的时候写的,现在拿出来晒晒————————————————————————————混淆才是王道,如果混淆再加密就更酷了.. ...

  2. java自定义classloader引发的思考

    引用 java类的热替换 classloader机制 如下图所示,java的classloader是双亲委派机制.会首先从父classloader加载指定的class,如果加载不到才会从子classl ...

  3. Java高级进阶:自定义ClassLoader

    假如我们的类不在classpath下,而我们又想读取一个自定义的目录下的class,如果做呢? 读取自定义目录的类 示例读取c:/test/com/test.jdk/Key.class这个类. pac ...

  4. Java复习总结(二)Java SE 面试题

    Java SE基础知识 目录 Java SE 1. 请你谈谈Java中是如何支持正则表达式操作的? 2. 请你简单描述一下正则表达式及其用途. 3. 请你比较一下Java和JavaSciprt? 4. ...

  5. 使用自定义 classloader 的正确姿势

    详细的原理就不多说了,网上一大把, 但是, 看了很多很多, 即使看了jdk 源码, 说了罗里吧嗦, 还是不很明白: 到底如何正确自定义ClassLoader, 需要注意什么 ExtClassLoade ...

  6. 《写给大忙人看的java se 8》笔记

    现在才来了解java8,是不是后知后觉了点? 新的编程技术,个人不喜欢第一时间跟进. 待社区已有实践积淀再切入似乎更划算些? 一点点精明的考虑. 不多说,上代码. //读<写给大忙人看的java ...

  7. Java Se:Java Security

    Java API中有很多都使用了SecurityManager,这到底是什么玩意?最近看公司的产品的源码,也有不少SecurityManager.AccessControlContext等相关的代码, ...

  8. 图解classloader加载class的流程及自定义ClassLoader

    图解classloader加载class的流程及自定义ClassLoader 博客分类: JVM JavaJVM虚拟机EXTSUN /** *  转载请注明作者longdick    http://l ...

  9. Java SE 6 新特性: 对脚本语言的支持

    2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Musta ...

随机推荐

  1. script引入js文件问题

  2. ArrayList和LinkedList的区别

    简单的说,ArrayList是顺序存储,而LinkedList是链式存储.

  3. API 开发实践

    整个2015年,如果要给自己打上一个标签的话,那应该就是 API. 在各个不同的系统中定制各种 API 框架. 在做商城对接各种电商 ERP 的 API 开发中,我采用的是兼容SHOPEX 的 API ...

  4. Oracle中的数据分页

    --数据分页脚本 --创建包含数据分页代码元素声明的包头结构create or replace package data_controlis type type_cursor_data is ref ...

  5. [moka同学笔记]Yii2.0显示页匿名函数设置$value

    匿名函数设置$value <?= GridView::widget([ 'dataProvider' => $dataProvider, 'columns' => [ // ['cl ...

  6. No.016:3Sum Closest

    问题: Given an array S of n integers, find three integers in S such that the sum is closest to a given ...

  7. 【Effective Java】6、使用复合优先于使用继承

    这个,不管是什么书都会这样说,因为常常我们并不需要继承,而只是想把类进行一定的扩展,而我们想扩展的属性或方法对应的类都有,这个时候如果两者是is a的关系,这种关系是确实存在的,那么就可以使用继承,不 ...

  8. Android异步回调中的UI同步性问题

    Android程序编码过程中,回调无处不在.从最常见的Activity生命周期回调开始,到BroadcastReceiver.Service以及Sqlite等.Activity.BroadcastRe ...

  9. bootstrap源码分析之scrollspy(滚动侦听)

    源码文件: Scrollspy.js 实现功能 1.当滚动区域内设置的hashkey距离顶点到有效位置时,就关联设置其导航上的指定项2.导航必须是 .nav > li > a 结构,并且a ...

  10. PyInstaller 安装方法 及简单的编译exe (python3)

    安装PyInstaller //地址 https://github.com/pyinstaller/pyinstaller/tree/python3 //上面的链接已经失效,新的(20160809更) ...