JVM学习笔记4—类加载机制及面试题整理

面试题

1、说说java类加载机制
2、JDK 动态类加载
3、如果加了final,是在类加载的什么时候分配的
4、Java类加载器有哪些,为什么使用双亲委派模型
5、类加载机制详细介绍一下,如何实现一个自定义类加载器
6、Java类加载器有哪些各个类加载器主要负责哪些部分的类加载?一个类的加载过程?一个自己实现的String类, 当new String时,这个String是jdk的String还是自己写的String?如何才能让ApplicationClassLoader加载自己写的String?

一、虚拟机类加载

我们在java编译器中编写的java代码要想在虚拟机上运行并不像我们表面看到的那么简单,它要经过一系列的处理过程才能实现在虚拟机上的最终运行。因为java虚拟机不和包括java在内的任何语言绑定,它只与Class文件这种特定的二进制文件格式所关联,因此我们首先要使用Java编辑器将Java代码编译为存储字节码的Class文件,如下图所示:

在这里插入图片描述
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制

类加载时机

类从被加载到虚拟机内存中开始,到卸载出内存位置,它的生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading) 七个阶段。


在这里插入图片描述
如编写面向接口的应用程序,可以等到运行时再指定实际的实现类。 在java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的。这种策略虽然会令加载是稍微增加一些性能开销,但是会为java程序提供高度的灵活性。 java里天生可以动态扩展语言的特性就是依赖运行期动态加载到和动态连接到这个特点实现的。

1、加载

1)什么情况下虚拟机需要开始加载一个类呢
 
虚拟机规范中并没有对此进行强制约束,这点可以交给虚拟机的具体实现来自由把握。类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它。类的加载是通过类加载器(Classloader)完成的,它既可以是饿汉式[eagerly load](只要有其它类引用了它就加载)加载类,也可以是懒加载[lazy load](等到类初始化发生的时候才加载)。不过我相信这跟不同的JVM实现有关,然而他又是受JLS保证的(当有静态初始化需求的时候才被加载)。

2)加载阶段干什么

加载阶段是类加载过程的第一个阶段。在这个阶段,JVM 的主要目的是将字节码从各个位置(网络、磁盘等)转化为二进制字节流加载到内存中,接着会为这个类在 JVM 的方法区创建一个对应的 Class 对象,这个 Class 对象就是这个类各种数据的访问入口

3)加载过程

  • 通过一个类的全限定名来获取其定义的二进制字节流。
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。

加载阶段完成后,虚拟机外部的 二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,这样便可以通过该对象访问方法区中的这些数据。

2、连接

注意: 连接阶段是与加载阶段交叉进行的(如一部分字节码得文件格式验证动作)。

1)验证

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  • 文件格式验证:主要验证字节流是否符合Class文件格式的规范,如果符合则把字节流加载到方法区中进行存储。

  • 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外、父类是否继承了不被允许的类。类中的方法是否与父类有矛盾等。

  • 字节码验证:最复杂的一个阶段。主要目的是通过数据量和控制流分析,确定程序语义是合法的,符合逻辑的。保证被校验类的方法在运行时不会做出危害虚拟机安全的事件。

  • 符号引用验证:符号引用中通过字符串描述的全限定名是否能找到对应的类。在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。符号引用中的类、字段、方法的访问性(private、protected、public、default)是否可被当前类访问。

2)准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。

  • 这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。 如: public static int value = 3 另外变量value在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的public static指令是在程序编译后,存放于类构造器()方法之中的,所以把value赋值为3的动作将在初始化阶段才会执行
  • 如果类字段的字段属性表中存在ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。如:public static final int value = 3 编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为3。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值