JAVA-类加载机制(3)-类加载器

类加载器

作用:通过类全限定名来获取二进制字节流

用例:类层次划分,OSGi,热部署,代码加密

1,类和类加载器

  任意一个类和加载该类的加载器一同确立在虚拟机中的唯一性;

  每个类拥有独立的类名称空间;

  判断两个类是否相等,必须建立在同一个类加载器加载的前提下;否则会影响:equals, isAssignableFrom, isInstance, instanceof结果

package com.classload.temp;

import java.io.IOException;
import java.io.InputStream;

public class MainTest {
    
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        
        ClassLoader myLoader = new ClassLoader(){
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {

                try {
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if(is == null){
                        return super.loadClass(name);
                    }
                    
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    throw new ClassNotFoundException(name);
                }
            }
        };
        
        Object obj = myLoader.loadClass("com.classload.temp.MainTest").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceof com.classload.temp.MainTest);
        
        /**
         * 执行结果: 
         *    class com.classload.temp.MainTest
         *    false                                  //obj使用了myLoader自定义类加载器,MainTest使用了应用程序类加载器,加载器不用所以为false
         */
    }
}

2,双亲委派模型

类加载器分类

方式一:①,启动类加载器: C++实现,是虚拟机自身一部分

      ②,其他类加载器:JAVA实现,独立于虚拟机外部,全部继承自抽象类java.lang.ClassLoader

方式二:①,启动类加载器:加载JAVA_HOME/lib目录,或被-Xbootclasspath指定路径下,并被虚拟机识别的类库加载到虚拟机内存中

               启动加载器不能被用户直接引用

               用户编写自定义类加载器,需要把加载请求委派给引导类加载器,自定义类加载器使用null代替即可

    ②,扩展类加载器:加载JAVA_HOME/lib/ext目录下,或被java.ext.dirs系统变量指定的路径下类库

             扩展类加载器可以直接被用户使用

             sun.misc.Launcher$ExtClassLoader实现

    ③,应用程序类加载器:加载用户类路径上所指定的类库

               该类加载器是ClassLoader中getSystemClassLoader()方法的返回值,有名系统类加载器

             该类加载器可以直接被用户使用

             sun.misc.Launcher$AppClassLoader实现

          

类加载器之间的关系使用了组合关系复用父类加载器代码,而不是继承;

双亲委派模型工作过程:

  如果一个类加载器收到类加载器的请求,首先不会自己尝试加载,而是将该请求委派给父类加载器完成,每个层次的类加载器都是如此;

  因此所有类加载请求最终都传送到顶层的类加载器中,只有当父类加载器无法加载时(搜索范围内未找到该类),子加载器才会去加载。

双亲委派模型优点:

  ①,java类随着它的类加载器一起具备了一种带有优先级的层次关系

    如:java.lang.Object存放于rt.jar中无论哪个类加载器加载该类,都会被委派到顶层启动类加载器进行加载,

        因此Object类在程序的各种类加载器中都是同一个类

    如:编写与rt.jar类库中同名的java类,可以正常编译但是永远无法被加载运行(因为双亲委派)  

  ②,双亲委派模型并不是强制性的约束模型    

双亲委派原理:

  1,检查该类是否被加载过

  2,没有加载过:

        父类加载器非空:调用父类加载器的loadClass()方法,

        父类加载器为空:默认使用启动类加载器作为父类加载器

        父类加载器加载失败:调用自己的findClass()方法加载

3,破坏双亲委派模型

原文地址:https://www.cnblogs.com/wanhua-wu/p/6577178.html