详解Java中的实例初始化块(IIB)

时间:2022-09-22 16:47:10

在 java 语言中的类初始化块 文章中我们简单的介绍了下 java 中的实例初始化块 ( iib )。不过我觉得介绍的有点简单了,于是,再写一篇文章详细介绍下吧。

java 语言中,存在三种操作:方法 、构造函数 和 初始化块。

其中初始化块又分为 实例初始化块 ( iib ) 和 静态初始化块。本章节,我们主要介绍实例初始化块。

实例初始化块 用于初始化实例变量。

实例初始化块 会在初始化类的一个实例时执行,而且在构造函数之前就执行。并且每次创建类的对象时它们都会执行。

实例化块的语法

实例初始化块一般放在构造函数之前,使用大括号 {} 扩起来的代码。语法结构一般如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class javatester
{
  // 实例化块
  {
    system.out.println("iib block");
  }
   
  // 构造函数
  javatester()
  {
    system.out.println("constructor called");
  }
  public static void main(string[] args)
  {
    javatester a = new javatester();
  }
}

注意,实例化块并不是类的必须。只是一个可选项。用于抽出构造函数的公共部分单独执行而已。

这段代码是可以编译运行的,运行结果如下

?
1
2
3
[yufei@www.twle.cn java]$ javac javatester.java && java javatester
iib block
constructor called

一个类中包含多个实例初始化块

类中的 实例初始化块 并不是类所必须的,而且,不限数量。一个类既可以没有实例初始化块,也可以有多个实例初始化块。

如果一个类有多个实例初始化块,那么它们会按照顺序从上到下依次执行,也就是说,定义在类顶部的实例初始化块最先执行。

我们来看一段代码,下面的类 javatester 定义了多个实例初始化块。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class javatester
{
  {
    system.out.println("iib1 block 1 ");
  }
   
  {
    system.out.println("iib2 block 2");
  }
    
  javatester()
  {
    system.out.println("constructor called");
  }
    
  {
    system.out.println("iib3 block 3");
  }
   
  public static void main(string[] args)
  {
    javatester a = new javatester();
  }
}

运行上面这段代码,输出结果如下

?
1
2
3
4
5
[yufei@www.twle.cn java]$ javac javatester.java && java javatester
iib1 block 1
iib2 block 2
iib3 block 3
constructor called

父类中的初始化块

在 java 语言的继承体系中,父类同样可以有初始化块,而且数量不限。

父类的实例初始化块在子类的构造函数中调用 super() 之后立即运行。编译器会在执行当前类的实例初始化块之前先执行父类的实例初始化块。

是不是很绕口,我们写一段代码来演示下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class b
{
  b()
  {
    system.out.println("b-constructor called");
  }
  
  {
    system.out.println("b-iib block");
  }
  
}
 
public class javatester extends b
{
  {
    system.out.println("javatester iib1 block 1 ");
  }
   
  {
    system.out.println("javatester iib2 block 2");
  }
    
  javatester()
  {
    super();
    system.out.println("javatester-constructor called");
  }
    
  {
    system.out.println("javatester iib3 block 3");
  }
   
  public static void main(string[] args)
  {
    javatester a = new javatester();
  }
}

运行以上范例,输出结果如下

?
1
2
3
4
5
6
7
[yufei@www.twle.cn java]$ javac javatester.java && java javatester
b-iib block
b-constructor called
javatester iib1 block 1
javatester iib2 block 2
javatester iib3 block 3
javatester-constructor called

从运行的结果来看,当创建类 javatester 的对象时,编译器尝试执行类 javatester 的构造函数。但因为它有一个父类,在发现了 super() 语句后,就转而先执行父类的构造函数。

因此,在继承体系中,实例初始化块和构造函数的执行顺序如下

执行父类的实例初始化块

执行父类的构造函数

执行当前类的实例初始化块

执行当前类的构造函数

实例初始化块的要点

我们一起来回顾下实例初始化块的要点。

每次创建新实例时都会运行实例初始化块

初始化块按它们在类中出现的顺序运行

如果存在父类,则首先会实例化父类然后在调用当前类的实例初始化块,最后再调用当前类的构造函数。