在平常学习中我们经常会碰到代码块和构造器的问题,下面我用一个简单的例子来解释它的运行机制。
我们先建立三个类,它们的关系是
Animal (Brid的父类)
|
Brid (Eagle的父类)
|
Eagle
代码如下:
①
public class Animal {
static{
System.out.println("Animal的static代码块");
}
{
System.out.println("Animal的普通代码块");
}
public Animal(){
System.out.println("Animal的无参构造器");
}
}②
public class Brid extends Animal{
static {
System.out.println("Brid的static代码块");
}
{
System.out.println("Brid的普通代码块");
}
public Brid(){
System.out.println("Brid的无参构造器");
}
public Brid(String str){
this();
System.out.println(str);
}
}③
public class Eagle extends Brid{
static {
System.out.println("Eagle的static代码块");
}
{
System.out.println("Eagle的普通代码块");
}
public Eagle(){
super("Eagle实例调用Brid含参数构造器");
System.out.println("Eagle的无参构造器");
}
public Eagle(String str){
System.out.println("Eagle的含参数构造器");
}
public static void main(String[] args){
new Eagle();
new Eagle();
}
}运行以后得到的结果为:
Animal的static代码块 ---1
Brid的static代码块 ---2
Eagle的static代码块 ---3 前三行是在载入类的时候产生的
Animal的普通代码块 ---4
Animal的无参构造器 ---5
Brid的普通代码块 ---6
Brid的无参构造器 ---7
Eagle实例调用Brid含参数构造器 ---8
Eagle的普通代码块 ---9
Eagle的无参构造器 ---10 4到10行是创建第一个类对象时产生
Animal的普通代码块 ---11
Animal的无参构造器 ---12
Brid的普通代码块 ---13
Brid的无参构造器 ---14
Eagle实例调用Brid含参数构造器 ---15
Eagle的普通代码块 ---16
Eagle的无参构造器 ---17 在创建第二个类对象时由于已经载入了三个类,就可以直接创建了
我们来分析一下结果,当程序运行main主函数时,首先需要载入当前类,而在载入当前类之前需要载入父类,由于static代码块是类代码块,在载入类的同时会载入static代码块,这就产生了前三行。然后会创建当前类对象,首先会创建父类对象,普通代码块和构造器会在创建类对象时同时执行,创建第一个对象时产生了4到10行。创建第二个对象时由于已经载入了三个类,所以就不会出现前三行,直接产生了11到17行。
我们简述一下整个创建对象的过程:
首先要明白,要想创建子类对象就必须先建立其所有父类的对象
(1)new Eagle() 创建对象时,先检查Eagle类的构造器是否显示调用当前类或者父类构造器——Eagle无参构造器中显示调用了其父类的含参构造器,检查完后就上溯到父类Brid(由于显示调用了,就会覆盖子类隐式调用)(2)先检查Brid类的构造器是否显示调用当前类或者父类构造器——其含参构造器调用其无参构造器,检查完后就上溯到父类Animal(3)先检查Animal类的构造器是否显示调用当前类或者父类构造器——没有显示调用,继续上溯其父类,(此后不在控制台输出)依次类推直至上溯到Object类
(4)建立Animal对象,先执行普通代码块
Animal的普通代码块 ---4
Animal的无参构造器 ---5(5)建立Brid对象,由于其子类显示调用了其含参构造器,就不再调用无参构造器去创建对象了
Brid的普通代码块 ---6
Brid的无参构造器 ---7
Eagle实例调用Brid含参数构造器 ---8
(6)建立Eagle对象,由于已经显示调用了父类的含参构造器,即父类对象已创建,可得
Eagle的普通代码块 ---9
Eagle的无参构造器 ---10创建第二个Eagle对象时,会重复以上创建过程,就可以得到以上结果。
相信大家都已经了解了构造器的运行机制了。