其实这类的问题,最好的方法就是自己写一下.
把可以有执行语句的地方写上打印语句,打印字符串用以标记分类.- class Root
- {
- static{
- System.out.println("Root的静态初始化块");
- }
- {
- System.out.println("Root的普通初始化块");
- }
- public Root()
- {
- System.out.println("Root的无参数的构造器");
- }
- }
- class Mid extends Root
- {
- static{
- System.out.println("Mid的静态初始化块");
- }
- {
- System.out.println("Mid的普通初始化块");
- }
- public Mid()
- {
- System.out.println("Mid的无参数的构造器");
- }
- public Mid(String msg)
- {
- //通过this调用同一类中重载的构造器
- this();
- System.out.println("Mid的带参数构造器,其参数值:"
- + msg);
- }
- }
- class Leaf extends Mid
- {
- static{
- System.out.println("Leaf的静态初始化块");
- }
- {
- System.out.println("Leaf的普通初始化块");
- }
- public Leaf()
- {
- //通过super调用父类中有一个字符串参数的构造器
- super("疯狂Java讲义");
- System.out.println("执行Leaf的构造器");
- }
- }
- public class Test
- {
- public static void main(String[] args)
- {
- new Leaf();
- new Leaf();
- }
- }
复制代码 问题点:
1. 静态初始化块
2.非静态初始化块
3. 构造器
所谓静态:
就是在类加载时,就随着类也加载了. 或者说,静态的成员都是类成员,随着类的加载而加载.
不像非静态成员变量,必须要创建对象.
那它们的运行顺序呢?
其实,上面的代码可以很清楚的看到结果.
1. 首先,通过new来创建对象,在此之前呢.会先初始化该类,又因为,java在加载某类时,会把该类的所以父类(至Object)都进行初始化操作.
2. 因为,static修饰的成员都是类成员,会随着类的加载而执行. 所以,会从最高父类执行静态初始化块,然后是其子类.就是把静态初始化块从上到下执行个遍.
3. 然后对象被创建了, 因为java的运行机制,所以还得再重复刚才的动作,不过这次是非静态初始化块和构造器.
4.非静态初始化块优先于该类构造器,但又因是父类,所以两者都优先于其子类执行. 过程就是,最高父类的非静态代码块 --> 构造器--> 其子类非静态代码块 --> 构造器
最后 执行到最底层的子类.
5. 又通过new创建了个对象,因为静态的成员已经存在,所以无须再次创建.只是再次执行非静态便可.把从第3步到 第4步重复一遍..
至此,整个程序运行结束! |