Java类中各成员的执行顺序

属性、方法、构造方法和自由块都是类中的成员,在创建对象时,各成员的执行顺序如下:
(1)父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
(2)子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
(3)父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
(4)执行父类构造方法。
(5)子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
(6)执行子类构造方法。
下面是示例代码:

  1. package 类成员执行顺序;
  2. public class Test {
  3.    public static void main(String[] args) {
  4.       new Son();
  5.    }
  6. }
  7. //父类Parent
  8. class Parent {
  9.    {
  10.       System.out.println("Parent的初始化块");
  11.    }
  12.    static {
  13.       System.out.println("Parent的static初始化块");
  14.    }
  15.    
  16.    public Parent() {
  17.       System.out.println("Parent的构造方法");
  18.    }
  19. }
  20. class Son extends Parent {
  21.    {
  22.       System.out.println("Son的初始化块");
  23.    }
  24.    static {
  25.       System.out.println("Son的static初始化块");
  26.    }
  27.    
  28.    public Son() {
  29.       System.out.println("Son的构造方法");
  30.    }
  31. }
上述代码的执行结果如下:
Parent的static初始化块
Son的static初始化块
Parent的初始化块
Parent的构造方法
Son的初始化块
Son的构造方法
-------------------------------------------------------------------

本文主要介绍以下两块内容的执行顺序,熟悉的大虾可以直接飘过。


     一。JAVA中执行顺序

  1. 静态块
  2. 构造器
  3. 父类构造器

    二。JAVA中赋值顺序

  1.       静态块直接赋值
  2.       块直接赋值
  3.       父类继承的属性已赋值
  4.       静态变量声明时赋值
  5.       成员变量声明时赋值
  6.       构造器赋值

 

 第一部分很好测试,我们只需要写一个子类,类中定义一个静态块,一个普通块,一个构造器,它的父类构造器,都打印一条语句,即可明白它们直接的执行顺序

 

Mastiff类

 

Java代码  收藏代码
  1. <span style="font-size: medium;">/** 
  2.  * 子类藏獒 
  3.  */  
  4. public class Mastiff extends Dog {  
  5.     public Mastiff() {  
  6.         System.out.println("Mastiff");  
  7.     }  
  8.   
  9.     {  
  10.         System.out.println("block");  
  11.     }  
  12.     static {  
  13.         System.out.println("static block");  
  14.     }  
  15.       
  16.     public static void  main(String[] args){  
  17.         Mastiff mastiff=new Mastiff();  
  18.           
  19.     }  
  20. }  
  21. </span>  

 

 

  DOG类

 

Java代码  收藏代码
  1. <span style="font-size: medium;">/** 
  2.  *DOG父类 
  3.  */  
  4. public class Dog {  
  5.     public Dog() {  
  6.         System.out.println("Dog");  
  7.     }  
  8. }  
  9. </span>  

 

运行结果为:

static block
Dog
block
Mastiff

 

也就是说,在我们的程序中,实例化一个类对象的时候,运行顺序为:

  1.   静态块
  2.   父类构造器
  3.   本类中的块
  4.   本类的构造器 

我们可以更进一步,如果在父类中也有块和静态块呢?

    DOG类改进后源码 

Java代码  收藏代码
  1. <span style="font-size: medium;">/** 
  2.  *DOG父类 
  3.  */  
  4. public class Dog {  
  5.     public Dog() {  
  6.         System.out.println("Dog");  
  7.     }  
  8.     static{  
  9.         System.out.println("super static block");  
  10.     }  
  11.       
  12.     {  
  13.         System.out.println("super block");  
  14.     }  
  15. }  
  16. </span>  

  

   Mastiff改进后源码

Java代码  收藏代码
  1. <span style="font-size: medium;">/** 
  2.  * 子类藏獒 
  3.  */  
  4. public class Mastiff extends Dog {  
  5.     public Mastiff() {  
  6.         System.out.println("Mastiff");  
  7.     }  
  8.   
  9.     {  
  10.         System.out.println("block");  
  11.           
  12.     }  
  13.     static {  
  14.         System.out.println("static block");  
  15.     }  
  16.       
  17.     public static void  main(String[] args){  
  18.         Mastiff mastiff=new Mastiff();        
  19.     }  
  20. }  
  21. </span>  

 

运行的结果为:

super static block
static block
super block
Dog
block
Mastiff

 也就是说此时的运行顺序为:

  1.    父类静态块
  2.    自身静态块
  3.    父类块
  4.    父类构造器
  5.    自身块
  6.    自身构造器 

     

      好了,知道了运行的顺序,那么这是为什么呢?

             这就要从JVM中类的装载机制和实例化机制开始说起,这里因为主题原因,先不讨论,有兴趣的同学可以自己查资料。

     

    我们再来讨论第二个问题,一个变量的值,它有可能在哪些地方确定呢??

    1. 从父类继承该值(包括:1.作为父类的成员变量已经赋值  2.在父类的块中赋值  3.在父类的构造器中赋值)
    2. 在构造器中对其进行赋值
    3. 在块中进行赋值
    4. 在方法调用中进行赋值

      现在假设在我们刚刚的例子中,有一个变量type,表示狗的品种

     

    Java代码  收藏代码
    1. <span style="font-size: medium;">/** 
    2.  *DOG父类 
    3.  */  
    4. public class Dog {  
    5.     public String type="父类成员变量赋的值";  
    6.     public Dog() {  
    7.         System.out.println("父类构造器--type-->"+type);  
    8.         type="父类构造器赋的值";  
    9.                    System.out.println("父类构造器----type--->"+type);  
    10.     }  
    11.       
    12.     {  
    13.         System.out.println("block---type--->"+type);  
    14.         type="父类块赋的值";  
    15.     }  
    16. }  
    17. </span>  

     

       

    Java代码  收藏代码
    1. <span style="font-size: medium;">/** 
    2.  * 子类藏獒 
    3.  */  
    4. public class Mastiff extends Dog {  
    5.     public String type="成员变量赋的值";  
    6.     public Mastiff() {  
    7.         System.out.println("构造器---type--->"+type);  
    8.         type="构造器赋的值";  
    9.     }  
    10.       
    11.     public void say(){  
    12.         System.out.println("say---type---->"+type);  
    13.     }  
    14.   
    15.     {  
    16.         System.out.println("block---type--->"+type);  
    17.         type="块赋的值";  
    18.           
    19.     }  
    20.       
    21.     public static void  main(String[] args){  
    22.         Mastiff mastiff=new Mastiff();  
    23.         mastiff.say()</span><span style="font-size: medium;">;</span><span style="font-size: medium;">        
    24.     }  
    25. }  
    26. </span>  

       

     

     执行结果如下:

    block---type--->父类成员变量赋的值
    父类构造器--type-->父类块赋的值
    父类构造器----type--->父类构造器赋的值
    block---type--->成员变量赋的值
    构造器---type--->块赋的值
    say---type---->构造器赋的值

     

    答案很明显,赋值顺序为:

    1. 父类成员变量赋值
    2. 父类块赋值
    3. 父类构造器赋值
    4. 自身成员变量赋值
    5. 自身块赋值
    6. 自身构造器赋值

     

     

     结合我们前面说的程序中的执行顺序,这个显然是很好理解的:

       1.成员变量赋值>>>块赋值>>>构造器赋值

       2.父类的块>>父类构造器>>自身块>>自身构造器


     又因为一个成员变量是不可能在静态变量中赋值的,而且又前面程序执行顺序可知

        静态块>>块

     

     

    所以,程序的赋值步骤为

    1. 父类的静态变量赋值
    2. 自身的静态变量赋值
    3. 父类成员变量赋值
    4. 父类块赋值
    5. 父类构造器赋值
    6. 自身成员变量赋值
    7. 自身块赋值
    8. 自身构造器赋值

    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
    红包 添加红包
    表情包 插入表情
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值