初始化块的基本用法,如果有一段初始化处理代码对所有对象完全相同,且无须接受任何参数,就可以把这段初始化处理代码提取到初始化块中。
实际上初始化块是一个假象,使用javac命令编译Java类后,该Java类中的初始化块会消失——初始化块的代码会被“还原”到每个构造器中,且位于构造器所有代码的前面
初始化块的语法格式如下:
[修饰符] {
// 初始化块的可执行性代码
...
}
修饰符只能是static,使用static修饰的初始化块被称为静态初始化块。
关于**静态初始化块、普通初始化块、构造器的先后顺序,我们举个例子来说明:
class Root
{
static {
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root()
{
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root
{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid()
{
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg)
{
// 通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:" + msg);
}
}
class Leaf extends Mid
{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf()
{
// 通过super调用父类中有一个字符串参数的构造器
super("hello");
System.out.println("执行Leaf的构造器");
}
}
public class Test
{
public static void main(String[] args)
{
new Leaf();
new Leaf();
}
}
输出结果如下图:
从上图看来,第一次创建一个Leaf对象时,因为系统中还不存在Leaf类,因此需要先加载并初始化Leaf类,初始化Leaf类时会先执行其顶层父类的静态初始化块,在执行其直接父类的静态初始化块,最后才执行Leaf本身的静态初始化块。
一旦Leaf类初始化成功后,Leaf类在该虚拟机里将一直存在,因此当第二次创建Leaf实例时无须再次对Leaf类进行初始化。
普通初始块和构造器的执行顺序与前面介绍的一致,每次创建一个Leaf对象时,都需要先执行最顶层父类的初始化块、构造器,然后执行其父类的初始化块、构造器……最后才执行Leaf类的初始化块和构造器。
Java系统加载并初始化某个类时,总是保证该类的所有父类(包括直接父类和间接父类)全部加载并初始化。.
静态初始化块和声明静态成员变量时所指定的初始值都是该类的初始化代码,他们执行顺序与源程序中的排列顺序相同。