转自 http://xtu-tja-163-com.iteye.com/blog/770401
在类生命周期里面分析过,类首先要被加载,形成一个Class实例,然后进行动态连接,然后进行初始化、实例化等,最后在类型不可触及时,被卸载收集。然而类是被什么加载到JVM内存里的呢?当然是类加载器。下面,详细分析下类加载器。
文章参考:http://weiwu83.iteye.com/blog/141207 (这位同学排版且整理的比较乱,我重新整理下)
超好的资料:
http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html
类加载器种类
类加载器包括JVM自带的加载器和自定义加载器。首先,看看JVM自带的加载器种类及作用范围:
1.启动类加载器(Bootstrap):加载JVM的类加载器,它是采用本地代码实现的,如C/C++等。它涉及到了具体JVM的本地实现细节,所以,开发者无法获得该加载器的引用。它负责将%JAVA_HOME%/lib目录下的类库加载到内存中;
2.标准扩展类加载器(Extension):开发者可以使用这种类型的加载器来加载类。它负责将%JAVA_HOME%/lib/ext或由系统变量 java.ext.dir 指定位置中的类库加载到内存中
3.系统类加载器(System):开发者可以使用这种类型的加载器来加载类。它负责将CLASSPATH指定的路径中的类库加载到内存中
4.用户自定义的类加载器:
具体的扩展以及系统类加载器继承结构图,看参考文章。
类的加载机制
JVM在加载类 时默认采用的是双亲委派机制。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
为了更好的理解类的加载机制,我们先来看看类加载器中几个重要的方法:
loadClass()方法:加载器的总调度方法。它会根据加载器双亲委派机制来选择适当的加载器加载出指定类名称的Class实例
findClass()方法:读取class文件形成一个字节数组,然后将该字节数组传递给 defineClass方法,试着导入这个类型,返回一个Class实例
defineClass方法:根据传入的资源,调用本地方法进行具体的类的加载过程。加载成功会返回一个Class实例
为了对这些方法有个大概的了解,现对JDK中自带的加载器类中的一些方法进行分析。首先,我们看看ClassLoader类中的findClass()的源码:
- protected synchronized Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- //首先验证这个类型是否已经被加载了
- Class c = findLoadedClass(name);
- if (c == null) { //如果还没被加载,则调用父加载器或启动类加载器类进行类加载
- try {
- if (parent != null) {
- //如果存在父类加载器,就委派给父类加载器加载
- c = parent.loadClass(name, false);
- } else {
- //如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方
- //native Class findBootstrapClass(String name)
- c = findBootstrapClass0(name);
- }
- } catch (ClassNotFoundException e) {
- // If still not found, then invoke findClass in order
- // to find the class.
- // 如 果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能
- c = findClass(name);
- }
- }
- if (resolve) {
- resolveClass(c);
- }
- return c;
- }
ClassLoader类中没有findClass方法的具体实现,但我们可以打开URLClassLoader类的源码,看看它的findClass具体实现:
- protected Class<?> findClass(final String name)
- throws ClassNotFoundException
- {
- try {
- return (Class)
- AccessController.doPrivileged(new PrivilegedExceptionAction() {
- public Object run() throws ClassNotFoundException {
- String path = name.replace('.', '/').concat(".class");
- //根据完整类名,读取Class文件内容
- Resource res = ucp.getResource(path, false);
- if (res != null) {
- try {
- //根据已读出的文件内容进行具体类型加载
- return defineClass(name, res);
- } catch (IOException e) {
- throw new ClassNotFoundException(name, e);
- }
- } else {
- throw new ClassNotFoundException(name);
- }
- }
- }, acc);
- } catch (java.security.PrivilegedActionException pae) {
- throw (ClassNotFoundException) pae.getException();
- }
- }
注意:本人写这文章的目的是为了加深了解以及为以后面试复习时用的,所以看起来不怎么详细。为了使感兴趣的朋友更加了解类加载器,我附上一份完整的资料,供大家参考
上面主要描述了类加载器的种类以及加载的规则,下章将分析下类加载器的特征以及程序的动态扩展