JVM是如何进行类加载的?

一个类只有被JVM虚拟机加载过后才能使用,虚拟机加载一个类需要进过:加载、链接、初始化这三步骤才能被使用。链接又分为:验证、准备、解析三个步骤。下面我将围绕这六个步骤进行讲解。

       加载:虚拟机将Class文件中的字节码加载到内存中,那虚拟机是如何将字节码加载到内存中的呢?答案是通过类加载器,说到类加载器,所有的类加载器都有一个共同的祖师爷(启动类加载器),启动类加载是由C++实现的,因此它没有对应的Java对象,所以在Java中只能用Null来指代,除了启动类加载器之外,其他的类加载器都是java.lang.ClassLoader的子类,因此有对应的Java对象,使用类加载器需要先加载它的父类类加载后才能使用,比如:只有启动类加载器,加载到虚拟机中后,其他的类加载器才能进行加载,当一个类需要加载时,类加载器会先让父类加载器加载,如果父类加载器无法加载,子类加载器才会尝试加载,这个规则叫双亲委派模型

       启动类加载器:加载的都是最基础、最重要的类,比如jre的lib目录下的jar包中的类,除了启动类加载器之外,还有扩展类加载器和应用类加载器,这三个类加载器是最重要的三个。

      扩展类加载器:它的父类加载器是启动类加载器,它主要负责加载相对于通用、次要的类,比如:jre的lib\ext目录下的jar包中的类。(注意,在Java9以后引入了模块系统,扩展类加载器改名为平台类加载器,所以,除了少数几个模块之外,其他模块都是由平台类加载器进行加载的

     应用类加载器:它主要加载应用程序下的类,

    链接:链接可以分为:验证、准备、解析三个阶段,Java虚拟机规范并没有要求在链接过程中完成解析。它仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要完成对这些符号引用的解析。

        验证阶段主要是验证字节码是否满足Java虚拟机的约束条件,

       准备阶段主要是为类的静态字段分配内存,当然除了给静态字段分配内存之外,部分Java虚拟机还会在此阶段构造其他跟类层次相关的数据结构,比如实现虚方法的动态绑定的方法表,

         解析是将符号引用解析成实际引用,当解析的这个符号引用所对应的类如果没有被加载,那么这里就会触发这个类的加载,但是未必会触发链接和初始化。(符号引用就是在Class文件被加载到Java虚拟机之前,这个类无法知道其他类以及其方法、字段所对应的具体地址,甚至不知道自己的方法、字段的地址,因此每当需要引用这些方法、字段或者类时,Java编译器会生成一个符号引用来代指。

  初始化:类加载的最后一步便是初始化,只要初始化以后这个类就可以被使用了,初始化主要是为标记为常量值的字段赋值,以及执行<clinit>方法的过程,在Java代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值,如果赋值的的静态字段是被flnal所修饰过的,并且它的类型是基本类型或者是字符串时,那么该字段便会被Java编译器标记为常量值,其初始化直接由Java虚拟机完成,除此之外的直接赋值操作,以及所有静态代码块中的代码,都会被Java编译器置于一个叫<clinit>的方法中,为了保证该方法只被执行一次,Java虚拟机会通过加锁来确保该方法只被执行一个。

类的初始化会在以下8种情况下触发:

       1.当虚拟机启动时,初始化用户指定的主类;

       2.当遇到用以新建目标类实例的new指令是,初始化new指令的目标类;

       3.当遇到调用静态方法的指令时,初始化静态方法所在的类;

       4.当遇到访问静态字段的指令时,初始化静态字段所在的类;

       5.子类初始化会触发父类的初始化;

       6.如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;、

       7.使用反射API对某个类进行反射调用时,初始化这个类;

       8.当初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类;

 

 

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值