jvm-类加载过程

1.类加载机制

类加载阶段:虚拟机要完成的3件事情:
1)通过一个类的完全限定名来 获取 此类的二进制字节流
2)将这个字节流所代表的静态 存储结构转化为方法区的运行时 数据结构
3)在 内存生产java.lang,Class对象,作为 换个类的各种数据访问入口。
在 Java 中默认提供了三个类加载器,分别是BootstarapClassLoader、ExtClassLoader、AppClassLoader,它们各自只负载加载规定目录内的Class文件,其中BootSrapCLassLoader 加载的目录为 JRE/lib/rt.jar 。ExtClassLoader 加载目录为JRE/lib/ext,appClassLoader 加载目录为classPath。

2.双亲委派制

双亲委派制就是当加载一个Class文件时会先交由上层ClassLoader来加载,如果发现已加载则直接返回,如果没有加载则去当前ClassLoader 的classes目录寻找该Class文件,找到则加载,找不到则交由下层ClassLoader来继续加载,如果直到最下层加载器都无法加载(找不到该Class文件)则抛出ClassNotFoundException异常。

3.类 加载过程

这里写图片描述
加载
通过类的全路径将这个类从外部加载到jvm中,同时在方法区生成该类的描述信息并在内存生成该类的Claas类型。作为方法区这个类的数据访问入口。
验证
字节码格式验证,如对jvm是否有害,释放符合当前虚拟机的要求 。
准备
为类的静态变量分配内存并根据这个静态变量所属的数据类型进行初始化。
解析
将符号引用替换成直接引用

初始化
在初始化阶段会调用类的初始化方法clinit()为静态变量赋予实际的值(例如将value赋值为123)、执行静态代码块。在 JVM 规范中没有强制约束加载的时机,不过对于初始化,JVM规范严格规定了有且只有5种情况必须立即对类进行初始化:
下面我们讲解 一下clinit()方法是怎么生成的。clinit()方法是编译器 自动收集类中的静态变量和静态语句所产生的。编译器收集的顺序是由语句出现的顺序 所 决定的,静态语句块只能复制定义在它后面的变量,但是不能使用,如下 图 所示,而且虚拟机规范保证,父类的clinit()方法一定 在子类之前执行,但不是 通过继承来的。
这里写图片描述

4.自定义类加载器:

public class CustomerClassLoaderTest  extends ClassLoader{
   private final String classDir;

    public CustomerClassLoaderTest(String classDir) {
        this.classDir = classDir;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String fileName = name;
        if (fileName.indexOf('.') != -1) {
            fileName = fileName.replaceAll("\\.", "\\\\");
        }
        fileName = fileName + ".class";
        try {
            try (FileInputStream in = new FileInputStream(classDir + fileName)) {
                try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer,0,len);
                    }
                    byte[] data = out.toByteArray();
                    return defineClass(name, data, 0, data.length);
                }
            }
        } catch (IOException e) {
            throw new ClassNotFoundException(name);
        }


    }



}

参考:
《深入理解Java虚拟机(第2版)》

猜你喜欢

转载自blog.csdn.net/the_one_and_only/article/details/81610310