块,就是 {} ,是可以在类里定义的第 4 种内容,与属性、方法、构造器属于平等的地位。允许在 {} 在里面写所有常规语句,包括输入输出、变量声明、运算表达、流程控制,它的主要作用就在于初始化类的属性和对象属性。

初始化块的执行时间

由于这个代码块没有方法声明、不能接受参数、返回,所以很明显它无法在类外部随意调用,所以它的执行只能在特定时间点运行——产生对象时。因此也被称为“实例初始化块”,每 new 一次类产生一个对象,就会被执行一次。
15.png
实例初始化块到底在“初始化”些啥?如果是初始化对象的话,那岂不是跟构造函数一样了?来讨论两个问题:

  1. 代码的执行顺序先后问题
  2. 哪些初始化动作放在初始化块,哪些动作放在构造方法?

    执行顺序

当构造函数和初始化块同时存在,执行顺序:

  1. 在内存中划分存储空间,用于存放对象
  2. 在该空间划分属性
  3. 执行实例初始化块中的代码
  4. 对属性初始化。这里的初始化是指有没有在声明属性时赋初值
  5. 执行构造函数中的代码

    1. // Car.java
    2. public class Car {
    3. public String name;
    4. public static int price = 100;
    5. public String color = "black";
    6. public Car(String name) {
    7. this.name = name;
    8. }
    9. public Car(String name, int price) {
    10. System.out.println("构造函数被执行前" + this.name + "," + this.color);
    11. this.name = name;
    12. this.price = price;
    13. System.out.println("构造函数被执行后" + this.name + "," + this.color);
    14. }
    15. // 初始化块
    16. {
    17. System.out.println("初始化块被执行前" + this.name + "," + this.color);
    18. System.out.println("初始化块被执行");
    19. System.out.println("初始化块被执行后" + this.name + "," + this.color);
    20. }
    21. }

    ```java // TestMain.java public class TestMain { public static void main(String[] args) {

    1. Car BMW = new Car("BMW", 100);

    } }

// 执行结果 / 初始化块被执行前null,black 初始化块被执行 初始化块被执行后null,black 构造函数被执行前null,black 构造函数被执行后BMW,black /

  1. ![16.png](https://cdn.nlark.com/yuque/0/2022/png/1454005/1652081650205-3ccdb7cc-bc00-4dea-b80a-56531bd393f0.png#clientId=uce1e1d96-9e28-4&crop=0&crop=0&crop=1&crop=1&from=ui&id=u8c2b99b5&margin=%5Bobject%20Object%5D&name=16.png&originHeight=1424&originWidth=2418&originalType=binary&ratio=1&rotation=0&showTitle=false&size=372185&status=done&style=stroke&taskId=uc833b3b7-41b1-4a76-ba58-b038d3e5cda&title=)
  2. <a name="Cp0IH"></a>
  3. ## 构造器和初始化块的分工
  4. 构造器的初始化主要通过外部调用者传入的参数给当前对象的属性赋值。若某些属性不需要从外部接收参数赋初始值,那么我们更多选用的是在声明属性时直接使用 = 赋值。<br />而实例初始化块,更多的作用是用于在特殊场景中执行非赋值的初始代码,例如:开启资源、开启通讯管道、开启文件、开启进程等等。
  5. <a name="kiqfS"></a>
  6. ## static 修饰或非 static 修饰的初始化块
  7. 初始化块也可以分 static 和非 static 修饰的。有 static 修饰的称为 “**静态初始化块**” ,没有 static 修饰的称为 “**实例初始化块**”。<br />嘿!找到一点规律没有?含有 static 的都叫 “静态XX 而没有 static 的则都叫 “实例XX
  8. ```java
  9. // Car.java
  10. public class Car{
  11. // 实例初始化块
  12. {
  13. }
  14. // 静态初始化块
  15. static{
  16. }
  17. }

静态初始化块,是在加载类时被执行。一个类在 JVM 中会且只会被执行一次(类加载),所以是首先被执行的,未来无论产不产生实例。而实例初始化块是在产生对象时被执行,和构造初始化块 new 一次执行一次。
17.png
如果说实例初始化块的执行时机和次数,与构造函数有一定的重叠,导致它的使用量很少,那静态初始化块由于其独特的执行时期(加载期)和执行次数(只执行一次)导致它无法被替换。

很多资源的操作包括开启、预加载都是一次性完成的,没有必要每 new 一个对象就做一次,所以通常我们会把这些操作放在程序的加载期而非运行期,这样就可以提升成都的运行速度。所以从使用频率来看,静态初始化块 多余 实例初始化块 甚至于从不会书写实例初始化块。

静态初始化也满足:

  1. 与类有关(在类加载时被执行)与对象无关(不能在内部访问对象的非静态内容,没有 this 当前对象)
  2. 代码在加载期被执行