初始化块
在进行静态块、构造块调用构造对象之前,我们需要先知道初始化块。
在一个类的声明中,可以包含多个代码块,只要构造类的对象,这些块就会被执行。
例如:
class Employee{
private static int nextId;
private int id;
private String name;
private double salary;
{
id = nextId;
nextId++;
}
...
}
在上列代码中无论使用哪个构造器构造对象,id域都在对象初始化块中被初始化。首先运行初始化块,然后才运行构造器主体部分。
静态初始化块
但是让类构造器行为依赖于数据域声明的顺序,会很容易引起错误。可以通过使用一个静态的初始化块来对静态域进行初始化。
将代码放在一个块中,并标记关键字static:
static{
Random generator = new Random();
nextId = generator.nextId(10000);
}
调用构造对象先后顺序
在编译器中输入下列代码
public class Test5 {
public Test5() {
System.out.println("构造函数");
}
static {
System.out.println("静态块");
}
{
System.out.println("构造块");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Test5 t = new Test5();
}
}
以下是程序执行的结果:
我们发现最先执行的是静态块然后是构造块最后才是构造函数。
我们再举一个例子验证一下是否是这个顺序:
public class EmployeeTest
{
public static void main(String[] args)
{
Employee tom = new Employee("tom",20);
System.out.println(tom);
System.out.println(tom.getId());
Employee jerry = new Employee("jerry",19);
System.out.println(jerry);
System.out.println(jerry.getId());
}
}
class Employee
{
private String name = "lisi";
{
System.out.println("初始化1");
name = "wangwu";
age = 20;
}
private int age = 30;
static{
System.out.println("静态初始化1");
id = 40;
System.out.println("id1:" + EmployeeTest.id);
System.out.println("liuliu开始");
Employee employee = new Employee("liuliu",50);
System.out.println(employee);
System.out.println("liuliu id:" + employee.getId());
System.out.println("liuliu结束");
}
private static int id = 30;
{
System.out.println("初始化2");
name = "zhaosi";
age = 40;
}
static {
System.out.println("静态初始化2");
id = 80;
}
public static int getId() {
return id;
}
public String getName()
{
return name;
}
public void setName(String name) {
this.name = name;
}
public Employee(String name,int age) {
super();
System.out.println("有参构造器");
this.name = name;
this.age = age;
}
public Employee() {
super();
System.out.println("无参构造器");
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + "]";
}
}
执行结果为:
根据结果发现我们的验证是正确的。
所以对于一个类的情况下,静态块、构造块和构造函数调用构造对象的先后顺序为:
1.静态块
2.构造块
3.构造函数
那么对于不是一个类,父类和子类关于它们的静态块、构造块、构造函数调用构造对象先后顺序是什么样子的呢?
我们可以写一个简单的例子:
class HelloA{
public HelloA() {
System.out.println("HelloA");
}
{
System.out.println("I am class A");
}
static {
System.out.println("static A");
}
}
public class HelloB extends HelloA{
public HelloB(){
System.out.println("HelloB");
}
{
System.out.println("I am class B");
}
static {
System.out.println("static B");
}
public static void main(String[] args) {
new HelloB();
}
}
以下是运行结果:
在同一个类中我们知道要调用构造函数时需要先加载整个程序,优先加载静态块执行。
而且在调用子类时会优先调用父类,也会优先加载父类,所以前两条为static A static B
调用子类构造函数时会优先调用父类构造函数,而构造函数调用,初始化块会先执行,构造函数后执行,所以才会出现I am class A HelloA
最后才是子类执行构造函数,调用构造函数之前会执行初始化块,所以最后两条为I am class A 、 I am class B