A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

本帖最后由 小鲁哥哥 于 2020-1-8 18:56 编辑

                点击查看济南黑马校区最新开班计划                                 

  
在继承中的三种代码块的执行顺序详细解释                


在我们Android基础班第八天,相信所有的同学都遇到了这样一道面试题目,题目是请问程序的执行结果,代码如下:
[Java] 纯文本查看 复制代码
class Test2_Extends {
        public static void main(String[] args) {
                Zi z = new Zi();
        }
}
class Fu {
        static {
                System.out.println("静态代码块Fu");
        }
        {
                System.out.println("构造代码块Fu");
        }
        public Fu() {
                System.out.println("构造方法Fu");
        }
}
class Zi extends Fu {
        static {
                System.out.println("静态代码块Zi");
        }
        {
                System.out.println("构造代码块Zi");
        }
        public Zi() {
                System.out.println("构造方法Zi");
        }
}
下面我们循序渐进的来研究一下这个题目,
首先我们先来讲讲什么是代码块
代码块就是用{}括起来的代码,根据代码块的功能、执行顺序和书写位置,我们把代码块分为  静态代码块,构造代码块,局部代码块。
  • 静态代码块:书写在成员位置, 大括号前面有static关键字,仅随着类的加载执行一次,所以可以在里面一些项目中的初始化的内容。
  • 构造代码块:书写在成员位置,每次创建对象的时候构造代码块都会执行一次,而且是在构造方法的内容执行之前执行,所以可以写一些该类里面所有构造方法共性的内容。
  • 局部代码块:书写在局部位置(即方法里面),可以尽早的让变量在内存中消失,略微提升一些效率
接着 , 我们按照上面对代码块的理解去分析一下这道的面试题的答案
首先执行 Zi z = new Zi();创建Zi类对象的时候,必须先加载Zi类的父类Fu,接着加载Zi类,那么Fu类和Zi类中的静态代码块就会随着类的加载而依次执行了,然后程序即将执行Zi类的构造方法,但是在构造方法执行之前必须先执行Zi类的构造代码块,接着执行Zi类的构造方法, 由于Zi类的构造方法第一行语句默认都有super(),所以接着将要去执行父类Fu的构造方法,但是在执行Fu的构造方法之前,先执行Fu的构造代码块,然后才能执行Fu的构造方法,执行Fu的这些内容后,才接着执行Zi类构造方法的后续内容。那照这样看来,执行结果应该是如下这样的
静态代码块Fu
静态代码块Zi
构造代码块Zi
构造代码块Fu
构造方法Fu
构造方法Zi

但是 , 事实并非如此,我们实际运行了一下 却发现执行结果是如下这样的:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi

这究竟是为什么呢?为什么和我们分析结果不一样呢?   这其实与构造代码块被编译到的位置有关。
接下来,我就利用反编译(反编译就是把class文件转成java文件)技术来解释一下这道面试题:首先介绍一个反编译工具"jd-gui.exe"(详见附件),打开反编译工具,将次此程序的class文件拖进反编译工具,你会发现反编译出来的代码和原来的代码有一些差异,代码如下
[Java] 纯文本查看 复制代码
class Test2_Extends
{
  public static void main(String[] paramArrayOfString)
  {
    Zi localZi = new Zi();
  }
}
class Fu
{
  public Fu()
  {
    System.out.println("构造代码块Fu");

    System.out.println("构造方法Fu");
  }

  static
  {
    System.out.println("静态代码块Fu");
  }
}
class Zi extends Fu
{
  public Zi()
  {
    System.out.println("构造代码块Zi");

    System.out.println("构造方法Zi");
  }

  static
  {
    System.out.println("静态代码块Zi");
  }
}
大家仔细查看反编译出来的代码 和原来的代码有什么区别呢
很明显,就是反编译出来的代码,构造代码块被写到了构造方法的最上面一行(别忘了这一行的上面还有super()呢),根据这个代码我们不难理解题目运行的结果
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi

其实讲到现在,我相信大家已经理解了上面的面试题,这道题最关键的理解点就是 构造代码块在编译期间其实是编译到了构造方法里面super()语句下面的位置


jd-gui-反编译工具.zip

690.29 KB, 下载次数: 264

java反编译工具

92 个回复

正序浏览
感谢楼主分享
回复 使用道具 举报
可明白了
回复 使用道具 举报
日子还是得过   加油吧我
回复 使用道具 举报
wain 初级黑马 2016-11-8 22:43:50
89#
贤哥威武!{:8_507:}
回复 使用道具 举报
回复 使用道具 举报
6666666666666666666666666666666
回复 使用道具 举报
666666666666666666666
回复 使用道具 举报
很好很强大,66666666666666666666
回复 使用道具 举报
签到,签到。
回复 使用道具 举报
签到    1
回复 使用道具 举报

为了黑马币!!!顶起!{:2_32:}
回复 使用道具 举报
签到,签到。
回复 使用道具 举报
谁给我点黑马比
回复 使用道具 举报
阿斯达所大所多阿萨德阿萨德阿萨德爱上大叔的
回复 使用道具 举报
子类在完成初始化前先完成对父类的初始化
回复 使用道具 举报
666666666666666666666
回复 使用道具 举报
重写tostring为什么呢/求大神指点,
回复 使用道具 举报
弄清楚程序执行时的加载顺序就OK了
回复 使用道具 举报
弄清楚程序执行时的加载顺序就OK了
回复 使用道具 举报
12345下一页
您需要登录后才可以回帖 登录 | 加入黑马