
面试官您好,关于类加载过程和双亲委派模型,我的理解如下:
类加载是指Java虚拟机(JVM)将类的.class文件中的二进制数据读入内存,并将其转换为运行时数据区中的方法区里的数据结构,最终在堆中创建一个代表该类的 java.lang.Class 对象,作为方法区该类各种数据的访问入口。
这个过程主要分为以下三个大阶段:加载、链接、初始化。其中链接又细分为三个子阶段。
1. 加载
java.lang.String)来获取定义此类的二进制字节流(可以从ZIP包、网络、运行时计算生成、数据库等来源获取)。
java.lang.Class 对象,作为方法区这些数据的访问入口。
2. 链接
链接阶段负责将加载到内存的类数据合并到JVM的运行时状态中,它包含三个步骤:
static修饰的变量),而不包括实例变量。
public static int value = 123; 在准备阶段过后的初始值是 0,而不是 123。将 value 赋值为 123 的 putstatic 指令是在初始化阶段才会执行的。
final static 修饰的常量(如 public static final int value = 123;),因为它在编译时就被分配了,准备阶段就会直接赋值为 123。
3. 初始化
这是类加载过程的最后一步,真正开始执行类中定义的Java程序代码(或者说字节码)。
<clinit>() 方法的过程。
<clinit>() 方法是什么?
<clinit>() 方法执行前,父类的 <clinit>() 方法已经执行完毕。因此,JVM中第一个被执行的 <clinit>() 方法的类肯定是 java.lang.Object。
<clinit>() 方法,但执行接口的 <clinit>() 方法不需要先执行父接口的。只有当父接口中定义的变量被使用时,父接口才会被初始化。
1. 什么是双亲委派模型?
双亲委派模型是Java类加载机制中的一种工作模式。它描述了类加载器在接到加载类的请求时,是如何协作的。
2. 工作原理
当一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
3. 类加载器的层次结构
<JAVA_HOME>/lib 目录下的核心类库(如rt.jar)。
<JAVA_HOME>/lib/ext 目录下的扩展库。
它们之间的关系是:应用程序类加载器的父加载器是扩展类加载器,扩展类加载器的父加载器是启动类加载器(注意,这里不是以继承关系实现的父子,而是使用组合关系来复用父加载器的代码)。
4. 双亲委派模型的作用
java.lang.Object 这样的核心类,在整个JVM环境中都是同一个类。相反,如果没有双亲委派,用户自己定义一个 java.lang.Object 类并放在ClassPath中,那系统中就会出现多个不同的Object类,Java体系的基础结构就乱了。
简单来说,类加载过程描述了一个 .class 文件从磁盘加载到JVM内存,并最终成为一个可用的 Class 对象的详细步骤。而双亲委派模型则是指导这些类加载器如何协同工作的一套规则,它的核心思想是“自上而下”的检查与“自下而上”的加载,从而保证了Java程序的稳定运行和安全。
我的回答完毕,谢谢。
ClassLoader 类的 loadClass() 方法(双亲委派的逻辑就在这个方法里)即可打破。更推荐的做法是重写 findClass() 方法,这样既不影响双亲委派模型,又能实现自定义的类加载逻辑。像Tomcat、JDBC等都因为特殊需求打破了双亲委派。
Class.forName() 和 ClassLoader.loadClass() 的区别?
Class.forName() 是一个静态方法,默认会执行类的初始化阶段。而 ClassLoader.loadClass() 是一个实例方法,只会进行加载阶段,不会进行初始化。Class.forName() 可以控制是否初始化。
new, getstatic, putstatic, invokestatic 这四条字节码指令时。2)使用 java.lang.reflect 包的方法对类进行反射调用时。3)当初始化一个类时,如果其父类还没有进行初始化,则需要先触发其父类的初始化。4)虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类。
如果小假的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。