jvm(2)---类加载机制

1.类加载:类加载器将class文件加载到虚拟机的内存
加载:在硬盘上查找并通过IO读入字节码文件
连接:执行校验、准备、解析步骤
校验:校验字节码文件的正确性
准备:给类的静态变量分配内存,并赋予默认值
解析:类装载器装入类所引用的其他所有类
初始化:对类的静态变量初始化为指定的值,执行静态代码块

2.类加载器

启动类加载器(BootstrapClassLoader):负责加载JRE的核心类库,如jre目标下的rt.jar,charsets.jar等
扩展类加载器(ExtensionClassLoader):负责加载JRE扩展目录ext中JAR类包
系统类加载器(ApplicationClassLoader):负责加载ClassPath路径下的类包
用户自定义加载器(CustomClassLoader):负责加载用户自定义路径下的类包

执行如下代码,查看对应的类加载器:

package com.nijunyang.spring;


import com.sun.crypto.provider.BlowfishCipher;

/**
 * @author: create by nijunyang
 * @date:2019/6/16
 */
public class ClassLoaderTest {
    public static void main(String[] args)
    {
        System.out.println(String.class.getClassLoader());
        System.out.println(BlowfishCipher.class.getClassLoader().getClass().getName());
        System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
        System.out.println(ClassLoader.getSystemClassLoader().getClass().getName());
    }
}

 

 可以看到String的类加载器null,因为String是在java核心包rt.jar里面这里面东西是由启动类加载器加载的,而启动类加载器是由C/C++实现的,根本不在JDK里面

BlowfishCipher的类加载器是ExtClassLoader,而这个类正是Jre扩展目录ext中jar包所在的类

3.类加载机制--全盘委托和双亲委派机制

全盘委托:当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也由这个ClassLoader载入,比如说A依赖B,那么B的加载器和A的加载器一样。

双亲委派:指先委托父类加载器寻找目标类,在找不到的情况下在自己的路径中查找并载入目标类,感觉说父类加载器不是很合适,因为没有这一层关系,感觉更像是上下级关系。委托上级加载器寻找目标类。

双亲委派的好处:

1.避免类重复加载,上级加载了,下级就不需要再加载

2.因为核心API都有固定的加载器,可以防止核心库被篡改: 自定义一个String类,同样在java.lang包下,运行代码会发现启动报错,实际加载的java.lang.String类并没有main方法,说明实际加载的String类并不是我们自定义的String类,而是因为双亲委派机制,往上委托到启动类加载器,去加载rt.jar里面的String类

4.类加载过程

实际上jvm对class文件是按需加载的,需要的时候才加载(运行时动态加载),并非一次全部加载进去,jvm启动参数加上:-verbose:class 查看类加载

package com.nijunyang.spring;


/**
 * @author: create by nijunyang
 * @date:2019/6/16
 */
public class ClassLoaderTest {
    static {
        System.out.println("静态块执行");
    }
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(3000);
        System.out.println(System.currentTimeMillis());
        new A();
        System.out.println("A对象创建完毕");
        new B();
    }
}

 

从结果中我们可以看到

1.从本地/E:/IdeaProject/tuling/spring/target/classes/下面去加载当前运行类ClassLoaderTest.class文件

2.初始化类,执行静态代码块

3.main方法运行,睡了5s之后打印当前时间,当我们new A的时候才去本地加载A.class文件到内存,再实例化A

4.A创建完毕之后,再去加载B.class,完成B的初始化

原文地址:https://www.cnblogs.com/nijunyang/p/11037605.html