类的实例化顺序:先是类初始化(执行类的静态初始化块),再是实例初始化(执行类的普通初始化块、构造器)
类初始化的顺序是:java.lang.Object类--->中间的父类......--->当前初始化的类(先执行最顶层父类的静态初始化块,然后依次向下,直到执行当前类的静态初始化块)
实例初始化的顺序是:java.lang.Object类--->中间的父类......--->当前初始化的类(先执行最顶层父类的普通初始化块、最顶层父类的构造器,然后依次向下,直到执行当前类的普通初始化块、当前类的构造器)
代码实例如下:
import static java.lang.System.*; class Root{ static{ out.println("Root类静态初始化块!"); } { out.println("Root类普通初始化块!"); } public Root(){ out.println("Root类无参数构造器!"); } } class Mid extends Root{ static{ out.println("Mid类静态初始化块!"); } { out.println("Mid类普通初始化块!"); } public Mid(){ out.println("Mid类无参数构造器!"); } public Mid(String name){ out.println("Mid类一个参数的构造器:name="+name); } } class Leaf extends Mid{ static{ out.println("Leaf类静态初始化块!"); out.println(); } { out.println("Leaf类普通初始化块!"); } public Leaf(){ out.println("Leaf类无参数构造器!"); } } public class Test{ public static void main(String[] args){ Leaf leaf=new Leaf(); } }
运行结果:
从结果可以看出,结果前三行为类初始化阶段执行的两个父类和自己类中的静态初始化块,后六行为类实例化阶段执行的两个父类和自己类中的普通静态初始化块、构造器。
把代码稍微改造一下,仔细体会其中的调用顺序变化:
import static java.lang.System.*; class Root{ static{ out.println("Root类静态初始化块!"); } { out.println("Root类普通初始化块!"); } public Root(){ out.println("Root类无参数构造器!"); } } class Mid extends Root{ static{ out.println("Mid类静态初始化块!"); } { out.println("Mid类普通初始化块!"); } public Mid(){ out.println("Mid类无参数构造器!"); } public Mid(String name){ //-改动:调用本类构造器 this(); out.println("Mid类一个参数的构造器:name="+name); } } class Leaf extends Mid{ static{ out.println("Leaf类静态初始化块!"); out.println(); } { out.println("Leaf类普通初始化块!"); } public Leaf(){ //-改动:调用父类一个参数构造器 super("张三"); out.println("Leaf类无参数构造器!"); } } public class Test{ public static void main(String[] args){ Leaf leaf=new Leaf(); } }
运行结果:
对Leaf类二次实例化:
import static java.lang.System.*; class Root{ static{ out.println("Root类静态初始化块!"); } { out.println("Root类普通初始化块!"); } public Root(){ out.println("Root类无参数构造器!"); } } class Mid extends Root{ static{ out.println("Mid类静态初始化块!"); } { out.println("Mid类普通初始化块!"); } public Mid(){ out.println("Mid类无参数构造器!"); } public Mid(String name){ //-改动:调用本类构造器 this(); out.println("Mid类一个参数的构造器:name="+name); } } class Leaf extends Mid{ static{ out.println("Leaf类静态初始化块!"); out.println(); } { out.println("Leaf类普通初始化块!"); } public Leaf(){ //-改动:调用父类一个参数构造器 super("张三"); out.println("Leaf类无参数构造器!"); out.println(); } } public class Test{ public static void main(String[] args){ Leaf leaf1=new Leaf(); Leaf leaf2=new Leaf();//-二次改动,第二次实例化 } }
运行效果:
总结:
1、Java加载并初始化某个类时,总是保证该类所有父类(包括直接和间接)全部加载并初始化
2、如上效果所示:类初始化成功后,会在虚拟机里一直存在,因此当第二次实例化时,不会再进行类初始化了