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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 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, 下载次数: 189

java反编译工具

点评

赞一个 0.0,顺便求 NIO 教程 0.0  发表于 2016-10-9 19:13

92 个回复

倒序浏览
不错,非常详细,收藏了
回复 使用道具 举报
回复 使用道具 举报
学习了            
回复 使用道具 举报
....................
回复 使用道具 举报
大神的教程贴,快来收藏啦!
回复 使用道具 举报
嗯嗯,收藏,
回复 使用道具 举报
{:5_275:}
回复 使用道具 举报
jayfan1991 来自手机 初级黑马 2016-10-7 12:43:37
9#
good.非常给力吆,加油
回复 使用道具 举报
jayfan1991 来自手机 初级黑马 2016-10-7 12:53:17
10#
不错不错,非常的好的咱
回复 使用道具 举报
居然有反编译工具..{:3_51:}
回复 使用道具 举报
看到很好就进来看看
回复 使用道具 举报
成功登陆系统
回复 使用道具 举报
赞一个,非常详细
回复 使用道具 举报
谢谢分享...嘎嘎嘎
回复 使用道具 举报
学习了 今天刚好学到这里
回复 使用道具 举报
非常好的啊资料
回复 使用道具 举报
dddddddddd
回复 使用道具 举报
爱黑马,爱生活……
回复 使用道具 举报
6666666666666
回复 使用道具 举报
12345下一页
您需要登录后才可以回帖 登录 | 加入黑马