Java中的类初始化解析

 更新时间:2023年08月14日 08:56:11   作者:IT_GJW  
这篇文章主要介绍了Java中的类初始化解析,类的初始化是一个Java类生命周期中的其中一个阶段,初始化是类加载的最后一个阶段,也正是在初始化阶段,才会真正开始执行类中所写的Java代码,需要的朋友可以参考下

类的初始化

类的初始化是一个Java类生命周期中的其中一个阶段。

如下图所示:

生命周期中的前五个阶段(加载、验证、准备、解析、初始化)是一个类在JVM中的完整加载过程。

初始化是类加载的最后一个阶段,也正是在初始化阶段,才会真正开始执行类中所写的Java代码。

Java虚拟机规范中严格规定了有且只有四种情况必须立即对类进行初始化:

1.遇到new、getstatic、putstatic、或者invoicestatic这4条字节码指令时,如果类没有进行过初始化,则需要触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象、读取或设置一个类的静态字段(被final修饰、已在编译期就把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

3.当初始化一个类的时候,如果发现父类还没有进行过初始化,需要先触发其父类的初始化。

4.当虚拟机启动时,用户需要指定一个主类(包含main方法的那个类),虚拟机会先初始化这个主类。

这四种场景中的行为称为对一个类进行主动引用,除此之外引用类的方式,都不会触发初始化,被称为被动引用。

初始化一个类时,最先执行的是静态域中代码,而静态域中包含静态变量、静态块和静态方法,其中需要初始化的是静态变量和静态块,这两者的执行顺序由代码的书写顺序决定。

静态域中的代码只会被执行一次。如果是使用new关键字实例化对象,静态域中的代码被执行后,紧接着会执行构造代码块和构造函数来实例化对象,这部分代码会执行多次,每次使用new关键字实例化对象时,这部分代码都会执行。可以用如下一段程序验证这些代码的执行顺序:

public class ClassInitTest {
    public static ClassInitTest c1 = new ClassInitTest();
    public static ClassInitTest c2 = new ClassInitTest();
    {
        System.out.println("构造代码块执行");
    }
    static {
        System.out.println("静态代码块执行");
    }
    public ClassInitTest(){
        System.out.println("构造方法被执行");
    }
    public static void main(String[] args){
        System.out.println("main方法的第一行被执行");
        ClassInitTest c = new ClassInitTest();
        System.out.println("main方法的第二行被执行");
    }
}

ClassInitTest是主类,当JVM启动时会对该类进行初始化,首先初始化静态域中的代码,可以看到首先是两个静态变量c1和c2,对c1、c2声明的同时进行变量值的初始化,其值是实例对象,因此构造代码块和构造方法会被执行,new了两次,因此会被执行两次。

紧接着会执行静态代码块中的代码。静态域中的代码执行完毕后便开始执行main方法,先是输出一行语句,接着又实例化了一个对象,构造代码块和构造方法会被执行,最后又输出一行语句。因此执行的结果如下:

如果存在继承的情况,初始化子类时,会先初始化父类,同时这几类代码执行顺序的优先级保持不变。实例代码如下:

public class Father {
    static {
        System.out.println("父类的静态代码块被执行");
    }
    {
        System.out.println("父类的构造代码块被执行");
    }
    public Father(){
        System.out.println("父类的构造方法被执行");
    }
}
public class Child extends Father{
    public Child(){
        System.out.println("子类构造方法被执行");
    }
    {
        System.out.println("子类的构造代码块被执行");
    }
    static {
        System.out.println("子类的静态代码块被执行");
    }
    public static void main(String [] args){
        new Child();
    }
}

执行结果如下:

之所以子类的构造方法执行前会先执行父类的构造方法,是因为子类的构造方法总是先调用父类的某个构造方法,也就是说,如果子类没有明显地指明使用父类的哪个构造方法,子类就调用父类不带参数的构造方法。

子类中使用super关键字调用父类的构造方法,而且super必须是子类构造方法的第一条语句,如果子类构造方法中没有明显地写出super关键字调用父类的哪个构造方法,那么默认在子类构造方法中有如下语句(即使不写):

super();//调用父类的无参构造函数

当然也可以在子类的构造方法中显式地用super语句指明调用父类的哪个构造方法(如果父类有多个构造方法的话)

super(实参列表);

到此这篇关于Java中的类初始化解析的文章就介绍到这了,更多相关Java类初始化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中的CyclicBarrier循环栅栏详解

    Java中的CyclicBarrier循环栅栏详解

    这篇文章主要介绍了Java中的CyclicBarrier循环栅栏详解,CyclicBarrier循环栅栏是用来进行线程协作,等待线程满足某个计数,构造时设置计数个数,每个线程执行到某个需要“同步”的时刻调用 await()方法进行等待,当等待的线程数满足计数个数时,继续执行,需要的朋友可以参考下
    2023-12-12
  • SpringBoot中的@ControllerAdvice注解原理详解

    SpringBoot中的@ControllerAdvice注解原理详解

    这篇文章主要介绍了SpringBoot中的@ControllerAdvice注解原理详解,在SpringBoot应用程序启动过程中,Spring会扫描所有的类,寻找带有@ControllerAdvice注解的类这些方法会被添加到一个映射表中,以便后续处理异常时能找到对应的处理方法,需要的朋友可以参考下
    2024-01-01
  • spring boot整合Cucumber(BDD)的方法

    spring boot整合Cucumber(BDD)的方法

    本篇文章主要介绍了spring boot整合Cucumber(BDD)的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • 基于Java事件监听编写一个中秋猜灯谜小游戏

    基于Java事件监听编写一个中秋猜灯谜小游戏

    众所周知,JavaSwing是Java中关于窗口开发的一个工具包,可以开发一些窗口程序,然后由于工具包的一些限制,导致Java在窗口开发商并没有太多优势,不过,在JavaSwing中关于事件的监听机制是我们需要重点掌握的内容,本文将基于Java事件监听编写一个中秋猜灯谜小游戏
    2023-09-09
  • 详解Spring中@Component和@Configuration的区别

    详解Spring中@Component和@Configuration的区别

    一直有同学搞不清Spring中@Component和@Configuration这两个注解有什么区别,所以这篇文章小编就给大家简单介绍一下@Component和@Configuration的区别,需要的朋友可以参考下
    2023-07-07
  • Java流形式返回前端的实现示例

    Java流形式返回前端的实现示例

    ​ Java后端开发项目时,需要给前端传一些数据,本文主要介绍了Java流形式返回前端的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • 深入解析Java的Spring框架中bean的依赖注入

    深入解析Java的Spring框架中bean的依赖注入

    这篇文章主要介绍了Java的Spring框架中bean的依赖注入,讲解了以构造函数为基础的依赖注入和基于setter方法的依赖注入的方式,需要的朋友可以参考下
    2015-12-12
  • Spring中的集合注入代码实例

    Spring中的集合注入代码实例

    这篇文章主要介绍了Spring中的集合注入代码实例,集合注入是指在Spring框架中,通过配置文件或注解的方式将集合类型的数据注入到Bean中,集合类型包括List、Set、Map和Properties等,需要的朋友可以参考下
    2023-11-11
  • MyBatis 多个条件使用Map传递参数进行批量删除方式

    MyBatis 多个条件使用Map传递参数进行批量删除方式

    这篇文章主要介绍了MyBatis 多个条件使用Map传递参数进行批量删除方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java类加载策略之双亲委派机制全面分析讲解

    Java类加载策略之双亲委派机制全面分析讲解

    这篇文章主要介绍了Java双亲委派机制,双亲委派模型是Java加载类的机制,采用双亲委派模型的好处是Java类随着它的类加载器一起具备了一种带有优先级的层级关系,通过这种层级关系可以避免类的重复加载,感兴趣的朋友可以参考下
    2023-12-12

最新评论