JVM进阶——加载-链接-初始化以及类的初始化过程

在类加载机制的五个阶段中,我们已经讲完了第一个阶段。剩下的四个阶段由于涉及到比较多的类文件相关的知识,现在讲了会看得很吃力,所以我们暂时不会一一的去细讲,只说一下大概的用处,让大家有个概念性的认识。 
  装载之后的阶段就是校验阶段了,该阶段的目的就是确保上一阶段读进来的二进制字节流中包含的信息符合虚拟机的规范,并且不会危害虚拟机自身。校验主要分为四个方向:文件格式校验、元数据校验、字节码校验和符号引用校验。 
  校验过后就是准备阶段了。该阶段就是为类变量分配内存以及设置初始值。注意:这里的分配内存和设置初始值针对仅仅只是类变量,如:public static int val = 123;这种被static修饰的变量,但是这个设置初始值并不是将例子中的123设置给val变量,而是将0设置给该变量。因为这里指的是初始值,也就是默认的值。如boolean型默认的就是false;float型默认的就是0.0f;引用类型就默认为null。 
  然后就是解析阶段,该阶段就是将符号引用替换为直接引用的过程。这两个名词我们会在后面讲类文件格式的时候仔细讲,大家先记着有这么一个阶段就好了。 
  最后就是初始化的阶段了,到了这个阶段才会开始执行我们自己写在类中的代码。他执行的是类变量和静态块。如下面代码: 
这里写图片描述 
  还记得刚刚讲的准备阶段吗?在准备阶段是为类变量设置初始值和分配内存(方法区分配),而在该阶段则是为该变量赋上我们自己设置的值。到此,小伙伴知道为什么类方法(静态方法)不能调用普通方法或者普通变量了吗?因为类变量以及静态块各相关方法都在准备阶段分配了内存,在初始化阶段就赋予了值,而此时其他普通的变量并没有做到这几步,他们都是在生成实例变量的时候才会进行内存的分配(堆中分配),因此如果静态方法调用了一个普通变量,而此时还没有创建该普通变量的对象,这就会导致系统错误。所以为了避免这种情况,就不允许那样调用了。 
  这也是为什么main方法是静态方法的原因之一,因为不用创建对象就可调用了。创建对象是要消耗内存的!! 
  在类加载的前面四个阶段中,虚拟机都没有硬性的规定在什么情况下才能进行,而初始化阶段则有且只有5种情况下才能进行,基于易理解的角度来考虑,我们暂时只说3种:

  • 1:当虚拟机启动的时候,虚拟机会初始化包含main方法的那个类。
  • 2:当初始化一个子类的时候,发现其父类还没有初始化,就会先初始化其父类。
  • 3:当我们使用反射对类进行调用的时候,如何该类没有进行初始化,就会先初始化。在我们用JDBC的时候,我们经常会看到这样一行代码: 

  • Class.forName("com.mysql.jdbc.Driver"); 这就是反射调用,加载该类并且初始化。


  • java类的初始化过程


    一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。

    一.类加载时,变量的初始化顺序:
     1.首先,给静态成员变量分配内存空间,进行默认初始化
      (整型为0,浮点型为0.0,布尔型为false,字符型为'\u0000',引用型为null)
      
     2.其次,执行静态成员变量的初始化操作
      --静态成员的初始化,包括两种: 声明时直接初始化和静态代码块
      --执行顺序为:在代码中的出现的顺序(声明的顺序)
      
     注意: 1和2的动作,在类加载时只执行一次!!!!!!!

     

     如果创建了对象,则在堆中给类的实例分配内存空间,
     3.首先,对实例变量,进行默认初始化
      (整型为0,浮点型为0.0,布尔型为false,字符型为'\u0000',引用型为null)
      
     4.其次,执行实例变量的初始化操作
      --实例变量的初始化,使用前2种初始化方式: 声明时直接初始化和代码块
      --执行顺序为:在代码中的出现的顺序(声明的顺序)
     
     5.最后,执行构造函数(实例变量的第3中初始化方式)
     
    二.继承时,变量的初始化顺序:
     1.当类第一次使用时,JVM就会加载该类,如果该类存在父类,那么就先加载父类,这是一个递归过程,直到Object为止.
     在类加载中,首先进行静态成员变量按照默认值进行初始化,
     然后按照在类中声明的顺序执行静态代码块和静态变量的显示初始化.
     这个过程从父类到子类,并且只会执行一次!!!
     
     2.当父类与子类的静态代码初始化完成后,如果创建了类的对象,
     在初始化子类前,会先对其父类的实例变量进行默认初始化,
     然后按照在类中的声明顺序来执行代码块与实例变量的显示初始化,
     最后调用父类的构造函数,这也是一个递归过程,直到Object类为止.
     (这个过程在每次创建对象时,都会执行!!!)


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值