Java 使用构造器来对单个对象进行初始化操作,使用构造器先完成整个 Java 对象的状态初始化,然后将 Java 对象返回程序,从而让该 Java 对象的信息更加完整。而与构造器作用非常类似的是初始化块,它也可以对 Java 对象进行初始化操作。
1、使用初始化块
一个类里可以有多个初始化块,前面定义的初始化块先执行,后面定义的初始化块后执行。初始化块虽然也是 Java 类的一个成员,但是它没有名字,也就没有标识,因此无法通过类、对象来调用初始化块。初始化块的修饰符只能是 static ,使用 static 修饰的初始化块被称为类初始块(静态初始块)。初始化块里可以包含任意执行语句,包括定义局部变量,调用其他对象的方法,以及使用分支和循环语句。
public class Person
{
//定义一个初始化块
{
int a = 6;
if( a > 4 )
{
System.out.println("Person定义的初始化块:局部定量a的值大于4");
}
System.out.println("Person定义的初始化块");
}
{
System.out.println("Person定义的第二个初始化块");
}
public Person
{
System.out.println("Person类的无参构造函数");
}
public static void main(String[] args)
{
new Person();
}
}
//Person定义的初始化块:局部定量a的值大于4
//Person定义的初始化块
//Person定义的第二个初始化块
//Person类的无参构造函数
初始化块只在创建 Java 对象时隐式执行,而且在执行构造器之前执行。
使用 javac 命令编译 Java 类后,该 Java 类中的初始化块会消失,初始化块中代码会被“还原”到每个构造器中,且位于构造器前面
2、关联性
初始化块可以说是构造器的补充,初始化块总是在构造器执行之前执行的。与构造器不同的是,初始化块是一段固定的代码,它不能接收任何参数。因此初始化块对同一个类的所有对象所进行的初始化处理完全相同,利用这一点,我们可以将一段对所有对象完全相同,且无须接收任何参数的初始化处理代码提取到初始化块中,这样能更好地提高初始化代码的复用,提高整个应用的可维护性。
3、静态初始化块
如果定义初始化块时使用了 static 修饰符,则这个初始化块就变成了静态初始化块,也被称为类初始化块,可以对类进行初始化。静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象是执行。因此静态初始化块总是比普通初始化块先执行。因为静态初始化块属于类的静态成员,同样需要遵循静态成员不能访问非静态成员的规则,所以不能访问实例变量和实例方法。
下面程序创建三个类:Root、Mid 和 Leaf,这三个类都提供了静态初始化块和普通初始化块,而且 Mid 类里还使用 this 调用重载的构造器,而 Leaf 使用 super 显式调用其父类指定的构造器
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("和小陈一起学Java");
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 类进行初始化。
静态初始化块在以后编写 C3P0 数据连接池的工具类时会被运用到