一道阿里巴巴笔试题中,关于java中的变量,初始化快,构造函数初始化分析
2013-09-25 22:14
387 查看
本人菜鸟一只,断断续续学习java一年有余,之前一只都是转载各位大神的帖子,不敢献丑。前几天找工作遇到了一道笔试试题,让我困惑许久。查了一些资料,加上一些自己的理解,终于算是大体上明白了,也下决心写下自己的第一篇技术类博客(由于本人实在技术有限,如有错误,还请指正,感激不尽),当做是一个学习笔记吧,激励自己不断进步。
笔试试题是,给出下面代码的输出:
这道题当时做的是一塌糊涂。笔试结束忍不住在自己电脑上跑了一下,得到了如下结果:
看到结果时我就懵了,最初学习java时不重视基础的弊端一下子显现了出来。上网查了好多资料,java程序初始化顺序解释比较好的是:当要载入类时(注意只会载入一次),先初始化类里的静态域声明变量为默认值,(即使是赋值了,int值也要为默认的0)然后按顺序的执行静态域和静态块;但是当此类有父类时,要先如果父类有静态域或者静态块,先执行父类的,再执行子类的;当执行完有关静态的东西时,就到了构造类实例时候,会先对实例域初始化为缺省值,然后执行实例块(用{}括起来的部分),然后执行构造方法;当此类有父类时,就应该先进入父类的构造方法执行内容,然后再回到子类构造方法里,然后再跳出子类构造方法,执行子类里的实例域和实例块,然后再回到子类构造方法里,执行子类构造方法里面的内容.(参见http://hi.baidu.com/londalonda/item/3c2b5f722f84bc44ef1e53a7)
例如:
输出结果为:
但是我所遇到的问题,尽管没有父类,但是初始化情况也很复杂。下面我就说下自己的理解(其中蓝色部分表示程序中的执行语句,黄色背景部分是对应的显示结果部分):
1、该程序加载完成后,在执行main函数前,先要初始化Test1类里面的静态变量,此时会初始化静态变量为默认值,即有:k=0,t1=null,t2=null,i=0,n=0。之后按照顺序开始执行静态变量的赋值操作有k=0。
2、接下来执行t1=new Test1("t1")。执行该条程序时,需要执行Test1类的构造函数。而按照类成员初始化的顺序,类内部的变量和实例块会在构造器被调用之前得到初始化。因此就需要按照先后顺序先初始化类变量j,再执行构造块,最后执行构造函数。执行public int
j=print("j");由于print方法被重写,所以得到输出结果1:j i=0 n=0(此处的i=0和n=0正好证明了静态变量在加载时只是完成了初始化,按照顺序还没有进行赋值),此时变为i=1,n=1。接着执行构造块部分,得到输出结果2:构造快
i=1 n=1,此时变为i=2,n=2。最后执行Test1的构造函数,得到输出结果3:t1 i=2 n=2,此时变为i=3,n=3。
3、现在执行t2=new Test1("t2")。执行该条程序时,步骤同上一步,在构造函数调用之前,再次调用类内部的变量和实例块。因而陆续执行了public
int j=print("j");和实例块部分。得到输出4:j i=3 n=3,此时变为i=4 n=4。5:构造快 i=4 n=4,此时变为i=5
n=5。6:t2 i=5 n=5,此时变为i=6 n=6。此处,特别注意,每次调用类的构造方法之前,该类的内部变量和实例块都会得到调用,验证如下:
得到输出结果为:
4、下面执行i=print("i")。得到输出7:i i=6 n=6,此时变为i=7 n=7。
5、下面执行n=99。此时变为i=7 n=99。
6、接着,执行静态块static{ print("静态块"); }。在执行main()函数前,还有执行静态块部分,因而输出8:静态块
i=7 n=99。然后变为i=8 n=100。
7、现在开始执行main()函数。通过1~6步,初始化完成,执行main函数。执行Test1 t=new Test1("init");按照之前所说,类的构造方法调用之前,还要先调用类内部变量和实例块。因而顺序执行public
int j=print("j");实例块代码和构造函数。得到结果9:j i=8 n=100。然后有i=9 n=101。运行实例块得到结果10:构造快 i=9 n=101。同时又i=10
n=102。运行构造函数得到结果11:init i=10 n=102。
至此程序完毕。从上不难发现,在每次构造函数运行前,类的实例变量和实例块部分都会得到执行,且执行顺序服从先后顺序。
笔试试题是,给出下面代码的输出:
public class Test1{ public static int k=0; public static Test1 t1=new Test1("t1"); public static Test1 t2=new Test1("t2"); public static int i=print("i"); public static int n=99; public int j=print("j"); { print("构造快"); } static{ print("静态块"); } public Test1(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++i;++n; } public static int print(String str){ System.out.println((++k)+":"+str+" i="+i+" n="+n); ++n; return ++i; } public static void main(String[] args) { Test1 t=new Test1("init"); } }
这道题当时做的是一塌糊涂。笔试结束忍不住在自己电脑上跑了一下,得到了如下结果:
1:j i=0 n=0 2:构造快 i=1 n=1 3:t1 i=2 n=2 4:j i=3 n=3 5:构造快 i=4 n=4 6:t2 i=5 n=5 7:i i=6 n=6 8:静态块 i=7 n=99 9:j i=8 n=100 10:构造快 i=9 n=101 11:init i=10 n=102
看到结果时我就懵了,最初学习java时不重视基础的弊端一下子显现了出来。上网查了好多资料,java程序初始化顺序解释比较好的是:当要载入类时(注意只会载入一次),先初始化类里的静态域声明变量为默认值,(即使是赋值了,int值也要为默认的0)然后按顺序的执行静态域和静态块;但是当此类有父类时,要先如果父类有静态域或者静态块,先执行父类的,再执行子类的;当执行完有关静态的东西时,就到了构造类实例时候,会先对实例域初始化为缺省值,然后执行实例块(用{}括起来的部分),然后执行构造方法;当此类有父类时,就应该先进入父类的构造方法执行内容,然后再回到子类构造方法里,然后再跳出子类构造方法,执行子类里的实例域和实例块,然后再回到子类构造方法里,执行子类构造方法里面的内容.(参见http://hi.baidu.com/londalonda/item/3c2b5f722f84bc44ef1e53a7)
例如:
public class TestExtend4 { public static void main(String[] args) { C c = new C(); //1 } } class A { static { System.out.println("1"); //2 } public A() { //7 System.out.println("2"); //8 } } class B extends A { static { System.out.println("a"); //3 } public B() { //6 System.out.println("b"); //9 } } class C extends B { static { System.out.println("I"); //4 } public C() { //5 System.out.println("II"); //11 } { System.out.println("yeah!"); //10 } }
输出结果为:
1 a I 2 b yeah! II
但是我所遇到的问题,尽管没有父类,但是初始化情况也很复杂。下面我就说下自己的理解(其中蓝色部分表示程序中的执行语句,黄色背景部分是对应的显示结果部分):
1、该程序加载完成后,在执行main函数前,先要初始化Test1类里面的静态变量,此时会初始化静态变量为默认值,即有:k=0,t1=null,t2=null,i=0,n=0。之后按照顺序开始执行静态变量的赋值操作有k=0。
2、接下来执行t1=new Test1("t1")。执行该条程序时,需要执行Test1类的构造函数。而按照类成员初始化的顺序,类内部的变量和实例块会在构造器被调用之前得到初始化。因此就需要按照先后顺序先初始化类变量j,再执行构造块,最后执行构造函数。执行public int
j=print("j");由于print方法被重写,所以得到输出结果1:j i=0 n=0(此处的i=0和n=0正好证明了静态变量在加载时只是完成了初始化,按照顺序还没有进行赋值),此时变为i=1,n=1。接着执行构造块部分,得到输出结果2:构造快
i=1 n=1,此时变为i=2,n=2。最后执行Test1的构造函数,得到输出结果3:t1 i=2 n=2,此时变为i=3,n=3。
3、现在执行t2=new Test1("t2")。执行该条程序时,步骤同上一步,在构造函数调用之前,再次调用类内部的变量和实例块。因而陆续执行了public
int j=print("j");和实例块部分。得到输出4:j i=3 n=3,此时变为i=4 n=4。5:构造快 i=4 n=4,此时变为i=5
n=5。6:t2 i=5 n=5,此时变为i=6 n=6。此处,特别注意,每次调用类的构造方法之前,该类的内部变量和实例块都会得到调用,验证如下:
public class Test5 { public static void main(String[] args) { // TODO Auto-generated method stub ObjA a1=new ObjA(); ObjA a2=new ObjA(); ObjA a3=new ObjA(); } } class ObjA{ { System.out.println("ObjA中实例块被执行"); } static { System.out.println("ObjA中静态块被执行"); } public ObjA(){ System.out.println("constructor in ObjA"); } }
得到输出结果为:
ObjA中静态块被执行 ObjA中实例块被执行 constructor in ObjA ObjA中实例块被执行 constructor in ObjA ObjA中实例块被执行 constructor in ObjA
4、下面执行i=print("i")。得到输出7:i i=6 n=6,此时变为i=7 n=7。
5、下面执行n=99。此时变为i=7 n=99。
6、接着,执行静态块static{ print("静态块"); }。在执行main()函数前,还有执行静态块部分,因而输出8:静态块
i=7 n=99。然后变为i=8 n=100。
7、现在开始执行main()函数。通过1~6步,初始化完成,执行main函数。执行Test1 t=new Test1("init");按照之前所说,类的构造方法调用之前,还要先调用类内部变量和实例块。因而顺序执行public
int j=print("j");实例块代码和构造函数。得到结果9:j i=8 n=100。然后有i=9 n=101。运行实例块得到结果10:构造快 i=9 n=101。同时又i=10
n=102。运行构造函数得到结果11:init i=10 n=102。
至此程序完毕。从上不难发现,在每次构造函数运行前,类的实例变量和实例块部分都会得到执行,且执行顺序服从先后顺序。
相关文章推荐
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析(update)
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 一道关于java线程中断的题目,求大神指导,昨晚的阿里巴巴笔试题
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 展讯的一道笔试Java题(关于静态初始化问题)
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 一道关于java 类初始化 成员初始化的笔试题的解析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 阿里巴巴2014校园招聘研发笔试一道JAVA附加题分析
- 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序
- 由一道面试题所想到的--Java实例变量初始化