美文网首页
【黑马程序员济南中心】继承中的构造代码块执行顺序

【黑马程序员济南中心】继承中的构造代码块执行顺序

作者: b06ee9db5ac0 | 来源:发表于2018-04-28 09:44 被阅读0次

    相信有很多的同学都遇到了这样一道面试题目,题目是请问程序的执行结果,代码如下:

    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文件拖进反编译工具,你会发现反编译出来的代码和原来的代码有一些差异,代码如下:

    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()语句下面的位置

    相关文章

      网友评论

          本文标题:【黑马程序员济南中心】继承中的构造代码块执行顺序

          本文链接:https://www.haomeiwen.com/subject/bswwlftx.html