关于类中静态块,静态方法,构造代码块,构造方法的执行顺序

时间:2021-07-14 16:25:11

题目要求:输出运行结果:

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

运行结果如下:

1:j   i=0    n=0

2:构造块   i=1    n=1

3:t1   i=2    n=2

4:j   i=3    n=3

5:构造块   i=4    n=4

6:t2   i=5    n=5

7:i   i=6    n=6

8:静态块   i=7    n=99

9:j   i=8    n=100

10:构造块   i=9    n=101

11:init   i=10    n=102

首先看到static关键字,脑子里面第一反应有几点,

1、公有属性,可以有类名称直接访问。

2、静态方法,可以有类名称直接方法。

3、静态方法或者属性,可以再对象实例化之前就调用

至于该题中,顺序执行,先执行public static int k =0 ;

因为没有输出不用考虑这个,接着public static Text t1 = new Text("t1") ;

t1对象初始化时先执行非静态方法或者非静态常量,顺序执行,接着运行构造参数,

根据程序来看应该打印三条记录,分别是

1:j   i=0    n=0

2:构造块   i=1    n=1

3:t1   i=2    n=2

接下来public static Text t2 = new Text("t2") ;同理,执行完之后继续执行static代码块或者赋值静态变量,在main()方法中new了一个新的实例,静态变量只执行一次,接下来就是顺序执行非静态方法---->构造方法。应该是这样的顺序,面试的时候我写的不完成,哎。

接着想到继承关系(extends)子类继承一个父类之后,对象初始化的顺序又是怎样?

我写了一个demo,大家共勉

[java] view plain copy
  1. class A{  
  2.     public static int k = 0 ;  
  3.     static {  
  4.         System.out.println("父类静态") ;  
  5.     }  
  6.     {  
  7.         System.out.println("父类构造代码块") ;  
  8.     }  
  9.     public A(){  //构造  
  10.         System.out.println("父类构造方法");  
  11.     }  
  12. }  
  13. class B extends A{  
  14.     static {  
  15.         System.out.println("子类静态") ;  
  16.     }  
  17.     {  
  18.         System.out.println("子类构造代码块") ;  
  19.     }  
  20.     public B(){  //构造  
  21.         System.out.println("子类构造方法");  
  22.     }  
  23. }  
  24. public class Demo {  
  25.     public static void main(String args[]){  
  26.         B b = new B() ;  
  27.     }  
  28. }  

输入结果如下:

父类静态

子类静态

父类构造代码块

父类构造方法

子类构造代码块

子类构造方法


可以看出:
        a.父类始终先调用(继承先调用父类),并且这三者之间的相对顺序始终保持不变
        b.因为静态代码块在类加载时执行,所以先输出的是父类和子类的静态
        c.调用B的构造方法创建对象时,构造块和构造方法会一起按顺序执行,还是父类的先调用



最后总结了几点:

[java] view plain copy
  1. 1 /*   
  2.   
  3. 2          * 几大原则   
  4.   
  5. 3          * 一、静态成员变量(Static)   
  6.   
  7. 4          *  1、静态成员变量为类变量,所有对象共享同一内存空间   
  8.   
  9. 5          *  2、静态成员变量的声明和定义仅在首次加载类时执行一次   
  10.   
  11. 6          *  3、首次加载类时首先对所有静态成员变量根据类型默认赋初值,然后再对有右值的附右值   
  12.   
  13. 7          * 二、静态初始块   
  14.   
  15. 8          *  1、静态初始化块仅在首次加载类时执行一次   
  16.   
  17. 9          * ······多个静态成员变量与静态始化快参照出现顺序先后执行······   
  18.   
  19. 10          * 三、动态成员变量   
  20.   
  21. 11          *  1、动态成员变量定义在每次实例化对象时在构造函数之前执行   
  22.   
  23. 12          * 四、动态初始化块   
  24.   
  25. 13          *  1、动态初始化块在每次实例化对象时在构造函数之前执行   
  26.   
  27. 14          * ······多个动态成员变量与动态初始化块参照出现顺序先后执行······   
  28.   
  29. 15          * 总结:总的来说,在不涉及继承的前提下,当首次加载类时,按照如下顺序执行   
  30.   
  31. 16          *  1、按照出现顺序先后执行静态成员变量定义与静态初始化块   
  32.   
  33. 17          *  2、按照出现顺序先后执行动态成员变量定义与动态初始化块   
  34.   
  35. 18          *  3、执行构造函数   
  36.   
  37. 19          *  再次实例化对象时只执行第23步即可   
  38.   
  39. 20          *    
  40.   
  41. 21          * ············成员变量与定义与初始化块先于构造函数执行·········   
  42.   
  43. 22          * 五、当涉及到继承时,按照如下顺序执行   
  44.   
  45. 23          *  1、执行父类的静态成员变量定义与静态初始化块,执行子类的静态成员变量定义与静态初始化块   
  46.   
  47. 24          *  2、执行父类的非静态成员变量定义与动态初始化块,执行父类构造方法   
  48.   
  49. 25          *  3、执行子类的非静态成员变量定义与动态初始化块,执行子类构造方法   
  50.   
  51. 26          * 另:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在调用父类构造函数中使用子类重写的方法