由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序

一、阿里巴巴笔试题:

 

[java] view plaincopy
 
 
  1. public class Test {  
  2.     public static int k = 0;  
  3.     public static Test t1 = new Test("t1");  
  4.     public static Test t2 = new Test("t2");  
  5.     public static int i = print("i");  
  6.     public static int n = 99;  
  7.     private int a = 0;  
  8.     public int j = print("j");  
  9.       
  10.     {  
  11.         print("构造块");  
  12.     }  
  13.   
  14.     static {  
  15.         print("静态块");  
  16.     }  
  17.   
  18.     public Test(String str) {  
  19.         System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
  20.         ++i;  
  21.         ++n;  
  22.     }  
  23.   
  24.     public static int print(String str) {  
  25.         System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
  26.         ++n;  
  27.         return ++i;  
  28.     }  
  29.   
  30.     public static void main(String args[]) {  
  31.         Test t = new Test("init");  
  32.     }  
  33. }  


输出:

 

 

[plain] view plaincopy
 
 
  1. 1:j    i=0     n=0  
  2. 2:构造块    i=1     n=1  
  3. 3:t1    i=2     n=2  
  4. 4:j    i=3     n=3  
  5. 5:构造块    i=4     n=4  
  6. 6:t2    i=5     n=5  
  7. 7:i    i=6     n=6  
  8. 8:静态块    i=7     n=99  
  9. 9:j    i=8     n=100  
  10. 10:构造块    i=9     n=101  
  11. 11:init    i=10     n=102  

 

二、我们暂且先不看这道题,先回忆一下代码块、构造函数执行顺序的基本知识:

总体规则:静态代码块 -> 动态代码块 ->构造函数

静态代码块只在第一次new的时候执行一次,之后不再执行;动态代码块在每次new的时候都执行一次。

在不涉及继承的情况下:

1.静态代码块和静态成员变量在加载代码时执行,只执行一次,按照它们出现的顺序先后执行;

2.动态代码块在每次实例化对象时执行,在构造函数之前执行,多个动态代码块按照它们出现的顺序先后执行;

在涉及继承的情况下:

1.执行父类的静态代码块和静态成员变量定义,执行子类的静态代码块和静态成员变量定义;

2.执行父类的动态代码块,执行父类的构造函数;

3.执行子类的动态代码块,执行子类的构造函数;

4.如果父类构造函数中用到的函数被子类重写,那么在构造子类对象时调用子类重写的方法;

代码:

 

[java] view plaincopy
 
 
  1. public class staticTest {  
  2.     public static void main(String[] args) {  
  3.         A a1 = new B();  
  4.     }  
  5. }  
  6.   
  7. class A{  
  8.     public A(){  
  9.         System.out.println("A constructor.");  
  10.         func();  
  11.     }  
  12.       
  13.     static{  
  14.         System.out.println("class A static block.");  
  15.     }  
  16.       
  17.     private int ai = getAi();  
  18.   
  19.     {  
  20.         System.out.println("class A dynamic block.");  
  21.     }  
  22.       
  23.     private static int asi = getAsi();  
  24.       
  25.     private int getAi(){  
  26.         System.out.println("class A dynamic int.");  
  27.         return 1;  
  28.     }  
  29.       
  30.     private static int getAsi(){  
  31.         System.out.println("class A static int.");  
  32.         return 0;  
  33.     }  
  34.       
  35.     public void func(){  
  36.         System.out.println("A.func()");  
  37.     }  
  38. }  
  39.   
  40.   
  41. class B extends A{  
  42.     public B(){  
  43.         System.out.println("B constructor.");  
  44.         func();  
  45.     }  
  46.       
  47.     static{  
  48.         System.out.println("class B static block.");  
  49.     }  
  50.       
  51.     private int bi = getBi();  
  52.       
  53.     {  
  54.         System.out.println("class B dynamic block.");  
  55.     }  
  56.       
  57.     private static int bsi = getBsi();  
  58.       
  59.     private int getBi(){  
  60.         System.out.println("class B dynamic int.");  
  61.         return 1;  
  62.     }  
  63.       
  64.     private static int getBsi(){  
  65.         System.out.println("class B static int.");  
  66.         return 0;  
  67.     }  
  68.       
  69.     public void func(){  
  70.         System.out.println("B.func()");  
  71.     }  
  72. }  


输出:

 

 

[plain] view plaincopy
 
 
  1. class A static block.  
  2. class A static int.  
  3. class B static block.  
  4. class B static int.  
  5. class A dynamic int.  
  6. class A dynamic block.  
  7. A constructor.  
  8. B.func()  
  9. class B dynamic int.  
  10. class B dynamic block.  
  11. B constructor.  
  12. B.func()  


三、对阿里巴巴笔试题的分析

 

 

[java] view plaincopy
 
 
  1. public static int k = 0;  
  2. public static Test t1 = new Test("t1");  


函数先执行到这里,在构造t1的过程中发生了什么呢,通过对程序打断点分析,我发现,程序并没有执行其中的静态代码块,而是执行非静态代码块,为什么呢?我的理解是,“静态代码块只在程序加载的时候运行,并且是按其出现顺序加载的”,而现在我们在构造一个新对象,属于程序加载的时候的一个分支,然后还会走回来继续加载剩下的未加载的静态代码块。所以在这次创建静态对象的过程中,之后执行其中的非静态代码块。

 

下面我们看到的两个*****中间的就是在执行该语句的过程中产生的分支:

**********

所以接下来执行的是:

 

[java] view plaincopy
 
 
  1. private int a = 0;  
  2. public int j = print("j");  

 

执行第二句的时候会调用

 

[java] view plaincopy
 
 
  1. public static int print(String str) {  
  2.     System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
  3.     ++n;  
  4.     return ++i;  
  5. }  


然后执行动态代码块:

 

 

[java] view plaincopy
 
 
  1. {  
  2.     print("构造块");  
  3. }  


然后调用构造函数:

 

 

[java] view plaincopy
 
 
  1. public Test(String str) {  
  2.     System.out.println((++k) + ":" + str + "    i=" + i + "     n=" + n);  
  3.     ++i;  
  4.     ++n;  
  5. }  


这个顺序就是“动态代码块->构造函数"。

 

*************

然后跳出该分支,继续加载静态代码块:

 

[java] view plaincopy
 
 
  1. public static Test t2 = new Test("t2");  


执行此句会重复上面两个********之间的分支,这里不再赘述。

 

然后是:

 

[java] view plaincopy
 
 
  1. public static int i = print("i");  
  2. public static int n = 99;  
  3.   
  4. static {  
  5.     print("静态块");  
  6. }  


最后执行main函数里面的部分,依次调用动态代码块和构造函数,不再赘述。

posted @ 2015-03-27 15:52  睡不醒的贤劲君  阅读(210)  评论(0编辑  收藏  举报