静态块、构造块、构造函数调用构造对象的先后顺序

初始化块

在进行静态块、构造块调用构造对象之前,我们需要先知道初始化块。
在一个类的声明中,可以包含多个代码块,只要构造类的对象,这些块就会被执行。
例如:

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

猜你喜欢

转载自blog.csdn.net/fight252/article/details/89234679
今日推荐