当创建任何Java对象时,程序总会先依次调用每个父类的静态代码块,之后在依次调用代码块,父类构造器执行初始化,最后才调用本类的代码块,构造器执行初始化。
public class StudyJavaInit {
public static void main(String[] args) {
Son son = new Son();
}
}
class Person{
static String sex = "男";
{
String action = "eat";
System.out.println("Person 类的代码块初始值的action:" + action);
}
static{
System.out.println("Person 类的静态代码块初始值的sex:" + sex);
String sex = "女";
System.out.println("Person 类的静态代码块重新赋值后的sex:" + sex);
}
String action = "sleep";
public Person() {
System.out.println("Person 类的无参构造器");
}
public Person(String age) {
this(); // 显示调用无参构造器
System.out.println("Person 类的一个参数构造器");
}
@Override
public String toString() {
return "Person{" +
"action='" + action + '\'' +
'}';
}
}
class Parent extends Person{
static String sex = "男";
static{
System.out.println("Parent 类的静态代码块初始值的sex:" + sex);
String sex = "女";
System.out.println("Parent 类的静态代码块重新赋值后的sex:" + sex);
}
{
String action = "eat";
System.out.println("Parent 类的代码块初始值的action:" + action);
}
String action = "sleep";
public Parent(String age, String name) {
this(name); // 显示调用Parent一个参数构造器
System.out.println("Parent带两个参数构造器");
}
public Parent(String name) {
super(name); // 显示调用Parent一个参数构造器
System.out.println("Parent带一个参数构造器");
}
}
class Son extends Parent{
static String sex = "男";
String action = "sleep";
{
System.out.println("Son 类的代码块初始值的action:" + action);
String action = "eat";
System.out.println("Son 类的代码块重新赋值后值的action:" + action);
}
static{
System.out.println("Son 类的静态代码块初始值的sex:" + sex);
String sex = "女";
System.out.println("Son 类的静态代码块重新赋值后的sex:" + sex);
}
public Son() {
super("java");
System.out.println("Son 的无参构造器");
}
public Son(String name) {
this();
System.out.println("Son 带一个参数构造器");
}
}
执行结果:
Person 类的静态代码块初始值的sex:男
Person 类的静态代码块重新赋值后的sex:女
Parent 类的静态代码块初始值的sex:男
Parent 类的静态代码块重新赋值后的sex:女
Son 类的静态代码块初始值的sex:男
Son 类的静态代码块重新赋值后的sex:女
Person 类的代码块初始值的action:eat
Person 类的无参构造器
Person 类的一个参数构造器
Parent 类的代码块初始值的action:eat
Parent带一个参数构造器
Son 类的代码块初始值的action:sleep
Son 类的代码块重新赋值后值的action:eat
Son 的无参构造器
所以只要在程序创建Java对象,系统总是先依次执行完父类静态代码块,然后调用最顶层父类初始化操作,包括初始化块和构造器,最后依次向下调用所有父类的初始化操作,最终执行本类的初始化操作返回本类的实例。
至于调用父类的哪个构造器执行初始化,则分为以下几种情况
1.子类构造器执行体的第一行代码使用super显示调用父类构造器,系统根据super里的传入的实参数来调用父类哪个构造器
2.子类构造器执行体的第一行代码使用this显示调用本类中重载的构造器,系统根据this里的传入的实参数来调用本类另一个重载构造器
3.子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参数的构造器
需要注意的式super调用用于显示调用父类的构造器,this调用用于显示调用本类中另一个重载构造器。super调用和this调用都只能在构造器中使用,而且super调用和this调用都必须作为构造器的第一行代码,因此构造器中的super调用和this调用最多只能使用其中之一,而且最多只能调用一次。