Java面试--JVM类加载

面试题:JVM类加载机制(阿里面试题)
面试题:类加载器的双亲委派模型的作用,能重复加载某个类吗(阿里面试题)

一、JVM 类加载机制详解
JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化:
这里写图片描述
加载
加载过程主要完成三件事情:
1、通过类的全限定名来获取定义此类的二进制字节流
2、将这个类字节流代表的静态存储结构转为方法区的运行时数据结构
在堆中生成一个代表此类的java.lang.Class对象,作为访问方法区这些数据结构的入口。
3、这个过程主要就是类加载器完成。(对于HotSpot虚拟而言,Class对象较为特殊,其被放置在方法区而不是堆中)
这里写图片描述
连接
1、验证:
一个类被加载之后,必须要验证一下这个类是否合法,比如这个类是不是符合字节码的格式、变量与方法是不是有重复、数据类型是不是有效、继承与实现是否合乎标准等等。总之,这个阶段的目的就是保证加载的类是能够被jvm所运行。
2、准备:
仅仅为类变量(static修饰的变量)分配内存空间并且设置该类变量的初始值(这里的初始值指的是数据类型默认的零值),这里不包含用final修饰的static,因为用final修饰的类变量在javac执行编译期间就会分配,同时要注意,这里不会为实例变量分配初始化。类变量会分配在方法区中,而实例变量会在对象实例化是随着对象一起被分配在java堆中
举例:

public static int value=33;

这据代码的赋值过程分两次,一是上面我们提到的阶段,此时的value将会被赋值为0;而value=33这个过程发生在类构造器的()方法中。
3、解析:
解析阶段主要是将常量池内的符号引用替换为直接引用的过程。符号引用是用一组符号来描述目标,可以是任何字面量,而直接引用则是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。通常而言一个符号引用在不同虚拟机实例翻译出来的直接引用一般不会相同。
和C之类的纯编译型语言不同,Java类文件在编译过程中只会生成class文件,并不会进行连接操作,这意味在编译阶段Java类并不知道引用类的实际地址,因此只能用“符号引用”来代表引用类。举个例子来说明,在com.sbbic.Person类中引用了com.sbbic.Animal类,在编译阶段,Person类并不知道Animal的实际内存地址,因此只能用com.sbbic.Animal来代表Animal真实的内存地址。在解析阶段,JVM可以通过解析该符号引用,来确定com.sbbic.Animal类的真实内存地址
初始化
这个阶段主要是对类变量初始化,是执行类构造器的过程。
换句话说,只对static修饰的变量或语句进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
二、类加载器
把类加载阶段的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作交给虚拟机之外的类加载器来完成。这样的好处在于,我们可以自行实现类加载器来加载其他格式的类,只要是二进制字节流就行,这就大大增强了加载器灵活性。
JVM提供了3种类加载器:
1、启动类加载器(Bootstrap ClassLoader):负责加载 JAVA_HOMElib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
2、扩展类加载器(Extension ClassLoader):负责加载 JAVA_HOMElibext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。
3、应用程序类加载器(Application ClassLoader):负责加载用户路径(classpath)上的类库。
三、JVM类加载机制
1、全盘负责
当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
2、类加载器的双亲委派模型
当一个类加载器收到一个类加载的请求,它首先会将该请求委派给父类加载器去加载,每一个层次的类加载器都是如此,因此所有的类加载请求最终都应该被传入到顶层的启动类加载器(Bootstrap ClassLoader)中,只有当父类加载器反馈无法完成这个类的加载请求时(它的搜索范围内不存在这个类),子类加载器才尝试加载。其层次结构示意图如下:
这里写图片描述
作用:
1、可以避免重复加载,父类已经加载了,子类就不需要再次加载
2、更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。
例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。
3、缓存机制
缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。


Java面试的完整博客目录如下:Java笔试面试目录

转载请标明出处,原文地址:https://blog.csdn.net/ 如果觉得本文对您有帮助,请点击顶支持一下,您的支持是我写作最大的动力,谢谢。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/jiong9412/article/details/125453377