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计算两个汉字相似度的实现方法

    Java计算两个汉字相似度的实现方法

    有时候我们希望计算两个汉字的相似度,比如文本的 OCR 等场景,用于识别纠正,本文给大家详细介绍了Java计算两个汉字相似度的实现方法,文中有详细的实现代码,需要的朋友可以参考下
    2023-11-11
  • Java开发或调用WebService的几种方式总结

    Java开发或调用WebService的几种方式总结

    java开发过程中,很多地方都会遇到数据传递,远程获取数据问题,这篇文章主要介绍了Java开发或调用WebService的几种方式的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • java对xml节点属性的增删改查实现方法

    java对xml节点属性的增删改查实现方法

    下面小编就为大家带来一篇java对xml节点属性的增删改查实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • Mybatis与Ibatis的区别

    Mybatis与Ibatis的区别

    这篇文章主要介绍了Mybatis与Ibatis的区别,需要的朋友可以参考下
    2016-05-05
  • Java中的FileWriter用法详解与实战记录

    Java中的FileWriter用法详解与实战记录

    这篇文章主要给大家介绍了关于Java中FileWriter用法的相关资料,包括写入字符数据到文件、字符数组和部分字符写入、配合BufferedWriter使用等方法,同时也解释了其与OutputStreamWriter,BufferedWriter的异同特性,适合简单的文件写入操作,需要的朋友可以参考下
    2024-10-10
  • Spring Boot 3.x 全新的热部署配置方式详解(IntelliJ IDEA 2023.1)

    Spring Boot 3.x 全新的热部署配置方式详解(IntelliJ ID

    这篇文章主要介绍了Spring Boot 3.x 全新的热部署配置方式(IntelliJ IDEA 2023.1),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Java魔法值处理的四种方式

    Java魔法值处理的四种方式

    这篇文章主要介绍了Java魔法值处理的四种方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • SpringBoot整合WebSocket的客户端和服务端的实现代码

    SpringBoot整合WebSocket的客户端和服务端的实现代码

    这篇文章主要介绍了SpringBoot整合WebSocket的客户端和服务端的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • 浅谈spring ioc的注入方式及注入不同的数据类型

    浅谈spring ioc的注入方式及注入不同的数据类型

    这篇文章主要介绍了浅谈spring ioc的注入方式及注入不同的数据类型,具有一定借鉴价值,需要的朋友可以参考下
    2017-12-12
  • Maven编译时缺少依赖,java:程序包org.apache.http不存在的问题

    Maven编译时缺少依赖,java:程序包org.apache.http不存在的问题

    这篇文章主要介绍了Maven编译时缺少依赖,java:程序包org.apache.http不存在的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05

最新评论