一、类加载流程

      类加载指的是一个.class文件的加载,在Java中.class文件可能是一个类,也可能是一个接口。此处都叫做类加载。整个类加载的过程即:加载→验证→准备→解析→初始化。

      在链接过程阶段,给对类变量(static修饰的)赋初始值(比如int型默认为0),在初始化阶段会给类变量赋值,执行静态代码块

       

Java 引用自定义arr SDK_后端

     类加载器,顾名思义就是用来加载类的,将类的字节码文件通过Io流从硬盘读到内存中,但是其作用不仅仅是加载类。因为对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。

Java 引用自定义arr SDK_java_02

二、java类加载器分类:

1、 启动(Bootstrap)类加载器

 启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必由于虚拟机是按照文件名识别加载jar包的,如rt.jar,如果文件名不被虚拟机识别,即使把jar包丢到lib目录下也是没有作用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。

2、 扩展(Extension)类加载器

扩展类加载器是指Sun公司(已被Oracle收购)实现的sun.misc.Launcher$ExtClassLoader类,由Java语言实现的,是Launcher的静态内部类,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库,开发者可以直接使用标准扩展类加载器。

3、系统(System)类加载器

也称应用程序加载器是指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

4、理解双亲委派模式
    在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,需要注意的是,Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象,而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式即把请求交由父类处理,它一种任务委派模式,下面我们进一步了解它。

三、自定义类加载器

  定义java类

public class ClassBean {

    private int age;

    private String name;

    public ClassBean() {
    }

    public void createBean() {
        this.age = 32;
        this.name = "LiuPing";
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
        return "ClassBean{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

使用javac命令编译ClassBean.java为ClassBean.class,字节码文件的内容如下(字节码查看工具 Binary Viewer):

Java 引用自定义arr SDK_Java 引用自定义arr SDK_03

Java 引用自定义arr SDK_java_04

自定义类加载器

public class MyClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try {
            //将ClassBean.class文件读入输入流
            inputStream = new FileInputStream("D:\\workplace\\java\\opensource\\YangApp\\src\\main\\java\\org\\cn\\fcw\\cls\\ClassBean.class");
            outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while (((len = inputStream.read(buffer)) != -1)) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.flush();
            byte[] bytes = outputStream.toByteArray();
            ///生成类文件
            return defineClass(name, bytes, 0, bytes.length);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(outputStream!=null){
                    outputStream.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return  null;
    }
}

测试类

public static  void  main(String[] arr){
        MyClassLoader myClassLoader=new MyClassLoader();
        try {
            ///Class.forName("org.cn.fcw.ClassLoaderBean");
            //生成ClassBean类,一定要带包名
            Class<?> classLoaderBean = myClassLoader.findClass("org.cn.fcw.cls.ClassBean");
            //通过反射调用默认构造器创建实例
            Object o = classLoaderBean.getDeclaredConstructor().newInstance();
            //获取ClassBean的createBean方法
            Method method = classLoaderBean.getMethod("createBean");
            //执行createBean方法
            method.invoke(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Java 引用自定义arr SDK_类加载器_05