Class
类
描述所有java类的类。内存里的每一个类字节码就是Class类的实例。不是对象,而是指.class文件在内存中的字节码,它代表了这个类。
ClassLoader
类
一般的装载过程
一般的类装载器是类名后加.class,然后在classpath中找。找到后把class文件的内容转换成类字节码(Unicode)传送给JVM。.class文件中的字符是用UTF-8存储的。类加载后,JVM把字节码编译成执行程序,再把索引存入到一个HashTable中。
开发人员可以自己编写类装载器,其实就是一个类字节码制造器。怎么实现无所谓,只要能提供类字节码就可以了。
类装载器使用委托模式
实例化类装载器时必须指定父装载器,默认情况下是AppClassLoader(它的父装载器是ExtClassLoader,ExtClassLoader的父装载器是Bootstrap,也就是null)。每一个类装载器装载时先委托父装载器装载,一级一级向上传,再一级一级返回来。这样如果父装载器装载过了,就会告诉子装载器已经装载过了,不用再装载了。这就是static属性的原理,因为static的变量是与类字节码相关的,而委托模式保证了JVM中只有一个该类的类字节码。
类装载器的注意事项
A、B两个类,A只能由子装载器装载。现在B由父装载器装载了,在B中想调用A类是找不到的。因为在一个类中调用其它类时会用装载它的装载器,而父装载器又不能委托子装载器。j
例,junit不能安装在JDK的ext目录下,因为测试时是junit的类调用被测试的类。
JDK
中类装载种类
Bootstrap装载器,它不是java文件,而是用本地代码编写的装载器,它的作用是装载java核心包中的类(rt.jar)。如果Class.getClassLoader返回的是null,装载它的就是BootStrap
ExtClassLoader 负责装载JDK目录/jre/lib/ext下的类。
AppClassLoader负责CLASSPATH环境变量指定路径中的类。
实现自己的类装载器
必须继承ClassLoader类
findClass()和loadClass()都可以装载一个类。loadClass()内部调用的findClass()。
l
oadClass()装载时,先委托父装载器装载,如果父装载器装载不了,在调用findClass(),这就是委托机制的实现原理。
如果直接调用findClass()就不能实现委托模式。
自己编写类装载器时,只要覆盖findClass()就可以保证委托模式不变。如果是覆盖loadClass()就不能保证委托模式了。
注意:
覆盖方法时,子类覆盖的方法抛出的异常只能不多于父类原始方法抛出的异常。并且子类抛出的异常只能是父类抛出异常的同类或者子类。
借助于自己的类装载器,造出一个与原来的类的函数完全一样的类字节码,它还是调用原来类的函数,但是这样就可以在制造字节码时添加进其他的方法实现上面的功能。这就就是AOP架构的实现原理。
以上转自RederJ的专栏。原文见:http://blog.csdn.net/rederj/
类装载器的委托模式
一般的类加载器层次为Bootstrap->ExtClassLoader->AppClassLoader,默认情况下,应用程序申请AppClassLoader装载类,AppClassLoader先查看自己是否加载过这个类,如果没有就委托他的上级ExtClassLoader来加载该类,ExtClassLoader也先看自己是否加载过该类,如果没有就委托他的上级Bootstrap加载该类,如果Bootstrap也没有加载该类,则尝试加载该类,如果不成功,则返回到下级ExtClassLoader,由他来尝试加载类,如果不成功,就返回AppClassLoader,由AppClassLoader尝试加载,不成功则返回加载失败,以上任一级只要加载成功就返回被加载类的引用。
类装载器链上的各个类不是父子关系,下层不一定是上层的子类。所有类装载器是个平行的链式结构。
运行时包(Runtime package)
由同一个类装载器装载的属于相同包的类构成了运行时包。判断某个操作是否由包权限,不只判断他是否属于同一个包,还判断他是否由同一个类装载器加载。