4.6.7 初始化块
前面已经讲过两种初始化数据域的方法:
在构造器中设置值
在声明中赋值
实际上,Java还有第三种机制,称为初始化块(initialization block)。在一个类的声明中,可以包含多个代码块。只要构造类的对象,这些块就会被执行。例如,
在这个示例中,无论使用哪个构造器构造对象,id域都在对象初始化块中被初始化。首先运行初始化块,然后才运行构造器的主体部分。
这种机制不是必须的,也不常见。通常,直接将初始化代码放在构造器中。
注释:即使域定义在类的后半部分,在初始化块中仍然可以为它设置值。Sun的Java编译器的某些版本错误地处理了这种情况(bug # 4459133)。这个bug在Java SE 1.4.1中已经得到修正。但是,为了避免循环定义,不要读取在后面初始化的域。具体的规则请参看Java语言规范的8.3.2.3节(http://java.sun.com/docs/books/jls)。这个规则的复杂度足以使编译器的实现者头疼,因此建议将初始化块放在域定义之后。
由于初始化数据域有多种途径,所以列出构造过程的所有路径可能相当混乱。下面是调用构造器的具体处理步骤:
1)所有数据域被初始化为默认值(0、false或null)。
2)按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块。
3)如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
4)执行这个构造器的主体。
当然,应该精心地组织好初始化代码,这样有利于其他程序员的理解。例如,如果让类的构造器行为依赖于数据域声明的顺序,那就会显得很奇怪并且容易引起错误。
可以通过提供一个初始化值,或者使用一个静态的初始化块来对静态域进行初始化。前面已经介绍过第一种机制:
如果对类的静态域进行初始化的代码比较复杂,那么可以使用静态的初始化块。
将代码放在一个块中,并标记关键字static。下面是一个示例。其功能是将雇员ID的起始值赋予一个小于10 000的随机整数。
在类第一次加载的时候,将会进行静态域的初始化。与实例域一样,除非将它们显式地设置成其他值,否则默认的初始值是 0、false或null。所有的静态初始化语句以及静态初始化块都将依照类定义的顺序执行。
注释:使用下面这种方式,在同伴们的面前显露一手:可以使用Java编写一个没有main方法的“Hello, World”程序。
当用java Hello调用这个类时,这个类就被加载,静态初始化块将会打印“Hello, World”。在此之后,会得到一个“main is not defined(没有定义)”的错误信息。不过,可以在静态初始化块的尾部调用System.exit(0)避免这一缺陷。
例4-5中的程序展示了本节论述的很多特性:
重载构造器
用 this(...) 调用另一个构造器
默认构造器
对象初始化块
静态初始化块
实例域初始化
例4-5 ConstructorTest.java
java.util.Random 1.0
构造一个新的随机数生成器。
返回一个0~n-1之间的随机数。
【责任编辑:
夏书 TEL:(010)68476606】