JVM类加载器
JVM类加载器加载一个类分三个步骤:加载,连接,初始化,其中连接又包括验证,准备,解析三个部分。
加载
每个java文件生成为一个.class文件,也就是字节码文件,在加载这个阶段将.class文案读入内存,为为之创建一个jaav.lang.class对象
连接
- 验证
确保.class文件的字节流包含的信息是否符合虚拟机的要求 - 准备
为静态变量分配内存空间 - 解析
虚拟机将常量池中的符号引用替换为直接引用的过程
初始化
为类的静态变量赋予初始值
类加载器种类
虚拟机设计团队把机子动作放到了JVM外部实现,以便让应用程序决定如何获取所需的类。JVM提供了三种类加载器:
- 启动类加载器(Bootstrap ClassLoader)
又称为引导类加载器,负责加载JAVA_HOME\lib 目录中的一些核心类库,或通过-Xbootclasspath 参数指定路径中的,由C++编写,无法通过程序得到。 - 扩展类加载器(Extension ClassLoader)
负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类
库,是启动类加载器的子类。 - 应用程序类加载器(Application ClassLoader)
负责加载用户路径(classpath)上的类库,通俗的讲也就是我们自己定义的那些类,是扩展类加载器的子类
JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader
实现自定义的类加载器
双亲委派
当一个类收到类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载器中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的class),子类加载器才会尝试自己去加载。
例如,我们需要加载一个我们自己定义的student类,它的类加载器是应用程序类加载器,那么应用程序类加载器会委托扩展类加载器进行加载,而扩展类加载器最终会委托启动类加载器帮我们进行加载,如果启动类加载器加载不了,在让扩展类加载器去加载,扩展类加载器加载不了,再让应用程序类加载器加载。
使用双亲委派的好处:保证了使用不同的类加载器最终得到的都是同样一个Object对象
注意:每一个类都有自己的一个类加载器,Student.class.getClassLoader()获得,可以通过Student.class.getClassLoader().getParent()获得父加载器类,也就是扩展类加载器,而启动类加载器,我们是无法直接获得的。
参考:https://blog.csdn.net/weixin_41751625/article/details/79357482