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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王春祥 中级黑马   /  2012-3-14 20:16  /  2564 人查看  /  10 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

涉及到子父类的程序执行的顺序有点乱,大家帮忙讲讲
下边这段程序
public class Test2 extends Test1
{
        {System.out.print("1");}
        Test2()
        {System.out.print("2");}
        static
        {System.out.print("3");}
        {System.out.print("4");}
        public static void main(String[] args)
        {
                new Test2();
        }
}
class Test1
{
        Test1()
        {System.out.print("5");}
        {System.out.print("6");}
        static
        {System.out.print("7");}
}
输出结果:7365142

这是我分析的:
main()是程序的入口,创建Test2的实例,要调用构造函数初始化,若加载Test2类要先执行其中的
static代码块,又因为Test2继承自Test1,要实现Test2的方法必须先实现其父类Test1的方法。也就
是说要先加载Test1,同理要先执行static代码块,先输出7,然后执行父类中的其它语句输出6,
进入Test1,先执行static代码块输出3。再执行构造函数输出2.分析的哪不对,其它语句为什
么执行了

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

10 个回复

倒序浏览
问题是你代码中写了一些{}代码块, 执行的顺序应该是 1父类静态 2子类静态 3父类{}代码块 ,4父类方法 5子类{}代码块 6子类方法。 也就是说{}起来的代码优先于非静态方法执行

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 段浩亮 于 2012-3-14 20:44 编辑

过程应该是这样的:Test2中有主函数先加载test2,因为test2继承test1所以加载test2之前要先加载test1这是第一步:把test1 test2加载进内存,类一加载进内存就会执行类中的静态代码块输出73  第二步执行test2中的静态主函数当读到new Test2();时就会调用test2的构造函数,因为子类构造函数第一行有默认的super();语句。所以会先执行test1中的构造函数,而代码块又优先于构造函数执行所以先输出6再输出5,然后再执行test2中的代码块,输出1,4最后执行构造函数test2中的输出语句输出2.   希望你能够明白

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
第一,当你创建了Test2的实例对象之后,这个类继承自Test1,这时候Test1就会先加载进内存,否则其子类就不能用父类的方法。
父类进入内存之后,他先加载了静态代码块,打出一个7,然后开始执行Test2中的静态代码块,打出一个3。好了这时候存在于方法区的静态方法都已经加载完了
第二,接着他就返回来继续加载Test1中构造代码块,打出一个6,然后是Test1中的构造函数,打出一个5.
第三,加载完父类之后,jvm返回Test2执行构造代码块,打出一个1,顺序执行构造代码块,接着打出一个4,最后加载了构造函数Test2中的2。

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
1 因为new建立用到了class类文件,所以会先找到class文件并加载到内存中,静态代码块是随着类的加载而加载的。
所以先输出的是父类和子类的的静态代码块
static
         {System.out.print("7");}
static
         {System.out.print("3");}
然后执行父类中的构造代码块:
{System.out.print("6");}
然后执行父类中的构造函数
Test1()
         {System.out.print("5");}
然后执行子类中的构造代码块
{System.out.print("1");}
{System.out.print("4");}
最后执行子类中的构造函数
Test2()
         {System.out.print("2");}
总的来说,父优先于子,静态代码块随着类的加载而加载。然后是 构造代码块 再次是构造函数。

评分

参与人数 1技术分 +1 收起 理由
房宝彬 + 1

查看全部评分

回复 使用道具 举报
你要清楚静态代码块  代码块  构造函数 在内存的加载顺序 就好理解了
   静态代码块是 随着类加载而加载的 是对类名.class 初始化的 是最先存在的  
   而  代码块  是对对象在类中的代码块中进行初始化的
   构造函数 是对对象所对应的构造函数进行初始化的
   最后才是给对象的引用赋对象在堆内存中的内存地址值得
       而你这又和继承关联起来   但还是按照这个顺序判断就不难理解了~~!
现在就看看你的代码   你是创建子类对象

   这要说一下java的设计思路  为什么子类构造函数默认第一行必须有个  super()  来调用父类的构造函数
这是因为 如果你调用子类的构造函数  来给一个变量赋值的话   如果super中有同样的变量  且 不把super() 放到第一行  
那么 你的赋值 就是失败的  因为你用子类构造函数初始化变量 下面又用super调用父类的构造函数 又给这个变量赋值  
那么  你用子类构造函数初始化  是不是显得多此一举了  就是 你赋值是1  但是最后结果却是  父类初始化的 2    1 2 是假设的
  所以同理 就可以知道静态代码块  和  代码块  是同样的道理。  必须先调用父类的静态代码块 和代码块  
   所以结果是   创建子类test2   先调用父类的static代码块  是7  再是子类static代码块  结果是3
                      然后是调用代码块  先调用父类代码块 结果是 6     初始化父类构造函数(这为什么是这样我也不懂,反正就记住顺序了)然后是子类代码块 结果是1  4
               再然后 就是子类构造函数  结果是2
子父类  里面这几个的顺序是
   先初始化父类的静态代码--->初始化子类的静态代码-->初始化父类的非静态代码--->初始化父类构造函数--->初始化子类非静态代码--->初始化子类构造函数
  最后 我也想问一下   为什么  父类的构造函数 优先于子类非静态代码块    求大神讲解啊  我就这一个疑惑
最后 我也想问一下   为什么  父类的构造函数 优先于子类非静态代码块    求大神讲解啊  我就这一个疑惑
最后 我也想问一下   为什么  父类的构造函数 优先于子类非静态代码块    求大神讲解啊  我就这一个疑惑

评分

参与人数 1黑马币 +3 收起 理由
房宝彬 + 3

查看全部评分

回复 使用道具 举报
段浩亮 发表于 2012-3-14 20:41
过程应该是这样的:Test2中有主函数先加载test2,因为test2继承test1所以加载test2之前要先加载test1这是第 ...

解决了我的疑惑了   3q
回复 使用道具 举报
贠(yun)靖 发表于 2012-3-14 20:59
解决了我的疑惑了   3q

客气了,互相学习嘛
回复 使用道具 举报
OMG 中级黑马 2012-3-14 21:21:09
9#
1,先父类后子类,这就是为什么子类能覆盖父类的变量或方法的原因;
2,先静态 后构造,因为加载类就加载静态;
3,先构造代码块,后构造函数,构造代码块不是拥有建立对象,也不是用于被调用,而是用于执行类的功能。

所以,7365142
父类的静态7—子类的静态3—父类构造代码块6—父类构造函数5—子类构造代码块1—子类构造代码块4—子类构造函数
回复 使用道具 举报
谢谢各位
回复 使用道具 举报
贠(yun)靖 发表于 2012-3-14 20:53
你要清楚静态代码块  代码块  构造函数 在内存的加载顺序 就好理解了
   静态代码块是 随着类加载而加载的  ...

因为在继承关系的时候,创建子类会先调用父类的构造函数, 隐身的加上super
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马