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类初始化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot后端数据校验实战操作指南

    SpringBoot后端数据校验实战操作指南

    在项⽬开发中,对于前端提交的表单,后台接⼝接收到表单数据后,为了保证程序的严谨性,通常后端会加⼊业务参数的合法校验操作来避免程序的⾮技术性 bug,这篇文章主要给大家介绍了关于SpringBoot后端数据校验的相关资料,需要的朋友可以参考下
    2022-07-07
  • IntelliJ IDEA本地代码提交到github网站不显示与本地不同步问题的解决办法

    IntelliJ IDEA本地代码提交到github网站不显示与本地不同步问题的解决办法

    今天小编就为大家分享一篇关于IntelliJ IDEA本地代码提交到github网站不显示与本地不同步问题的解决办法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Java实现HttpGet请求传body参数

    Java实现HttpGet请求传body参数

    这篇文章主要为大家详细介绍了Java实现HttpGet请求传body参数的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • Java中三种零拷贝的实现示例以及对比详解

    Java中三种零拷贝的实现示例以及对比详解

    这篇文章主要介绍了Java中三种零拷贝的实现示例以及对比详解,本文主要是介绍几种零拷贝的实现示例,以及与最传统的做一个对比,看看在效率上到底有多大的提升,需要的朋友可以参考下
    2023-12-12
  • Java 调用Restful API接口的几种方式(HTTPS)

    Java 调用Restful API接口的几种方式(HTTPS)

    这篇文章主要介绍了Java 调用Restful API接口的几种方式(HTTPS),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • Spring如何使用三级缓存解决循环依赖

    Spring如何使用三级缓存解决循环依赖

    在Spring框架中,循环依赖是指两个或多个Bean相互依赖,形成闭环,导致无法完成初始化,此问题仅存在于单例Bean中,而原型Bean会抛出异常,Spring通过三级缓存及提前暴露策略解决循环依赖:一级缓存存放完全初始化的Bean
    2024-11-11
  • 详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案

    详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案

    这篇文章主要介绍了详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • SpringMVC源码解读之HandlerMapping - AbstractUrlHandlerMapping系列request分发

    SpringMVC源码解读之HandlerMapping - AbstractUrlHandlerMapping系列re

    这篇文章主要介绍了SpringMVC源码解读之HandlerMapping - AbstractUrlHandlerMapping系列request分发 的相关资料,需要的朋友可以参考下
    2016-02-02
  • Spring Bean的8种加载方式总结

    Spring Bean的8种加载方式总结

    以前学习Spring框架的时候,总结了几种Bean的加载方式,不过老师说还有其它的加载方式,以下八种并不是全部,但也足以用来做很多事情了,希望对大家有所帮助
    2022-10-10
  • Java基础泛型详情

    Java基础泛型详情

    这篇文章主要介绍了Java基础泛型详情,泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,下面文章的详细介绍,需要的朋友可以参考一下
    2022-04-04

最新评论