【Java】 初始化对象顺序

在Java中,对象的初始化顺序遵循以下一般规则,按照它们被声明和定义的顺序来进行:

  1. 父类静态内容 (如果有继承发生):

    • 静态变量声明和静态初始化块按照它们在父类中出现的顺序执行。
  2. 子类静态内容:

    • 静态变量声明和静态初始化块按照它们在子类中出现的顺序执行。
  3. 父类非静态内容 (如果有继承发生):

    • 父类的非静态变量声明和非静态初始化块按照它们在父类中出现的顺序执行。
    • 父类的构造函数执行。
  4. 子类非静态内容:

    • 子类的非静态变量声明和非静态初始化块按照它们在子类中出现的顺序执行。
    • 子类的构造函数执行。

具体步骤如下:

  • 静态变量和静态初始化块

    静态变量和静态初始化块按照它们在类中的顺序进行初始化,这个过程只会在类加载时发生一次。

  • 实例变量和实例初始化块

    实例变量和实例初始化块按照它们在类中的顺序初始化,这个过程会在每次创建类的实例时发生。

  • 构造函数

    在实例变量和实例初始化块初始化之后,构造函数被执行。

举一个具体的例子:

csharp 复制代码
public class Parent {
    static {
        System.out.println("Parent static block");
    }

    {
        System.out.println("Parent instance block");
    }

    public Parent() {
        System.out.println("Parent constructor");
    }
}

public class Child extends Parent {
    static {
        System.out.println("Child static block");
    }

    {
        System.out.println("Child instance block");
    }

    public Child() {
        System.out.println("Child constructor");
    }
}

public class Test {
    public static void main(String[] args) {
        new Child(); // 创建Child类的实例
    }
}

这段代码的输出将会按以下顺序:

scss 复制代码
Parent static block
Child static block
Parent instance block
Parent constructor
Child instance block
Child constructor

静态内容(静态变量和静态初始化块)在类首次被加载到JVM时初始化。对于实例内容(实例变量、实例初始化块、构造函数),每次创建类的对象实例时都会初始化。优先初始化父类内容,然后是子类内容。

以下是Java对象初始化的顺序的图示概览。这个顺序适用于当一个类被实例化时JVM所执行的步骤:

diff 复制代码
+-------------------------------------------------------+
|         类加载(如果该类未被加载过)                  |
+-------------------------------------------------------+
| 1. 父类静态变量和静态初始化块(按声明顺序)            |
| 2. 子类静态变量和静态初始化块(按声明顺序)            |
+-------------------------------------------------------+
|                 创建对象实例                           |
+-------------------------------------------------------+
| 3. 父类实例变量声明和实例初始化块(按声明顺序)        |
| 4. 父类构造函数                                       |
|                                                       |
| 5. 子类实例变量声明和实例初始化块(按声明顺序)        |
| 6. 子类构造函数                                       |
+-------------------------------------------------------+

这个图表说明了在Java中,一个类从被加载到实例化的过程中不同初始化动作的顺序。注意,如果已经加载了父类,那么在子类被加载时,不会再次加载父类。类加载时,静态初始化只会执行一次。实例初始化每次创建对象时都会执行。

这个顺序保证了在父类构造函数执行之前,父类的实例变量已经被初始化,同样地,在子类构造函数执行之前,子类的实例变量已经被初始化。这是语言设计上确保对象正确构建的重要规则。

在Java中,静态初始化块(Static Initialization Block)和实例初始化块(Instance Initialization Block)是两种用于初始化类和对象状态的代码块。

静态初始化块

静态初始化块是一个在类中定义的,用大括号{}包围的代码块,并且它前面有static关键字。它用于初始化类的静态变量。在类被加载到JVM时,静态初始化块被执行,并且无论创建了多少对象实例,它只执行一次。

例如:

csharp 复制代码
class MyClass {
    static int staticVariable;
    
    static {
        staticVariable = 10;
        System.out.println("Static initialization block called.");
    }
}

实例初始化块

实例初始化块是一个在类中定义的,用大括号{}包围的代码块,没有static关键字。它在构造对象时执行,每次创建类的一个新实例时,实例初始化块都会执行,并且它在构造函数之前执行。实例初始化块可以用来初始化那些不能在声明时初始化的复杂实例变量。

例如:

csharp 复制代码
class MyClass {
    int instanceVariable;
    
    {
        instanceVariable = 20;
        System.out.println("Instance initialization block called.");
    }
    
    MyClass() {
        System.out.println("Constructor called.");
    }
}

在上面的例子中,每次使用new MyClass()创建对象时,实例初始化块先于构造函数执行。

使用场景

  • 静态初始化块通常用于初始化复杂的静态变量,或者在类首次加载时执行某些只需要进行一次的操作。
  • 实例初始化块用于在调用任何构造函数之前执行一些操作或初始化块。如果类包含多个构造函数,并且这些构造函数中有重复的初始化代码,可以将这些代码放入实例初始化块中以避免重复。

值得注意的是,实例初始化块并不是Java编程中的常用做法,因为多数情况下,初始化逻辑可以直接放到构造函数中。然而,静态初始化块由于其特殊的定位和初始化时机,在初始化复杂静态数据时是必要的。

相关推荐
427724001 小时前
IDEA使用git不提示账号密码登录,而是输入token问题解决
java·git·intellij-idea
chengooooooo2 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
李长渊哦2 小时前
常用的 JVM 参数:配置与优化指南
java·jvm
计算机小白一个2 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
南宫生5 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
计算机毕设定制辅导-无忧学长5 小时前
Maven 基础环境搭建与配置(一)
java·maven
风与沙的较量丶6 小时前
Java中的局部变量和成员变量在内存中的位置
java·开发语言
m0_748251726 小时前
SpringBoot3 升级介绍
java
极客先躯7 小时前
说说高级java每日一道面试题-2025年2月13日-数据库篇-请说说 MySQL 数据库的锁 ?
java·数据库·mysql·数据库的锁·模式分·粒度分·属性分
程序员侠客行7 小时前
Spring事务原理 二
java·后端·spring