public class Test{
private static Test tester = new Test(); //step 1
private static int count1; //step 2
private static int count2 = 0; //step 3
public Test(){ //step 4
count1++;
count2++;
System.out.println("" + count1 + count2);
}
public static Test getTester(){ //step 5
return tester;
}
public static void main(String[] args){
Test.getTester();
}
}问:以上代码执行的顺序~,输出的结果~这是我昨天面试时碰到的一题,我尽量还原了原题。先说一下,这里count1未初始化可不是我忘了,原题就是这么搞D~
正好我对这种带有自身类型的字段的情况有些迷糊,索性答曰:“有变量未初始化,编译器可能会报错”~我想问的是,如果忽略未初始化错误的话,以上代码执行顺序到底如何?
Test tester = new Test(); 吧。
System.out.println("" + count1 + count2); \\首先空字符串和count1进行运算,得到1,然后这个字符再和数字count2进行运算,此时得到一个新字符串,也就是本题结果:11
int count1 = 0;
int count2 = 0;tester = new Test(); count1 ++;
count2 ++;
输出 1 1count2 = 0;
最终结果为1 0,输出为1 1
再根据楼主问题补充两点:
1.本题的成员变量count1,不是final类型的,所以不是必须初始化,更不会编译错误
2.本题的执行顺序,就是创建对象(new)的基本顺序,先初始化static,然后构造方法.....
但是,我把count2的值改一下(不管改成什么),其结果总是:11
还有不管怎么改count1的值也是同样的情况,这是为什么啊?
我初学java,基础不够,望多多指教啊!!!
a, 首先装载这个类,然后在链接的准备阶段(链接包括验证、准备、引用三个阶段),为所有类(静态)变量分配内存,设为为默认值(Test tester = null; int count1 = 0; int count2 = 0;) b, 链接完成后,进行(类)初始化,按代码中声明顺序进行类(静态)变量的初始化,也就是先调用
private static Test tester = new Test(); //step 1
注:这里省略了基类初始化和<clinit>的相关细节。 c, 上述步骤中的new 触发Test类的实例化(对象创建),先在堆上分配内存,然后设置对象变量(本例中没有)为初始值,然后调用<init>,细节略过,简单来讲这里会导致构造方法的调用,也就是:
public Test(){ //step 4
count1++;
count2++;
System.out.println("" + count1 + count2);
}
很显然,这时候的count1和count2并没有被初始化,只是简单的被设置为默认值0(在链接的准备阶段)。所以打印出来的值总是11。 d, 接下来继续按声明顺序执行初始化,也就是:
private static int count1; //step 2
private static int count2 = 2; //step 3 e, 初始化完成之后,完成了初始类的加载,跳转到main方法开始执行。所以顺序为14253,并且无论count2 和 count1为多少,打印出来的总是11.;如果交换一下顺序,比如
count 2 = 2;
new test(); 那么打印的结果将是13.
的确是14235
只要注意在4的时候 private static int count1; //step 2
private static int count2 = 0; //step 3这2句话并没有被执行,所以count1 = count2 = 0;
完成++操作后,值都变为1.
所以不管怎样改变2,3中count1,count2的值,打印出来的总是1.
JVM规定当4中情况下会出事类,其中一种酒是调用类的静态方法的时候。所以很明显这里调用Test的静态方法getTester所以Test会进行初始化。那么static的部分会被触发。根据初始化的顺序,那么很明显应该执行:
private static Test tester = new Test();
然后
private static int count1
private static int count2
也会被初始化,但是由于他们是int型的,所以初始化为0
这里就是创建Test对象咯,接下来就是进入Test的构造方法,
count1++;
count2++;
System.out.println("" + count1 + count2);
由于count2还没有进行赋值,所以它目前为0;所以 ++后count1和count2都是1
然后接下来就不用再说了吧。
jvm加载class文件后,首先给静态变量 开辟空间然后初始化。所以123都符合,1我也党他是静态变量看了,这个比较迟疑。jvm把静态变量初始化完毕后,就调用构造方法,也就是4.最后才是调用方法。
=====================
我是这么理解的,不对的地方请直接说明。
你如果能理解类的加载顺序就清除了,就简单说你写的这个类,先加载静态变量,所以第一个是private static Test tester = new Test(); 但是你调用了构造方法,所以会去加载够着方法,这个时候另外两个静态变量并没有赋值。默认值为0,++操作后就是1了,输出结构是11;
楼主可以把main中的方法调用和getTester()方法去掉,运行空的main方法,结果应该一样。
仅仅个人理解
count1因为是字段,所以它会被分配默认值0
输出11
private static Test tester = new Test(); //step 1
private static int count1; //step 2
private static int count2 = 0; //step 3
public Test(){ //step 4
count1++;
count2++;
System.out.println("count1=" + Test.count1);
System.out.println("count2=" + Test.count2);
}
public static Test getTester(){ //step 5
return tester;
}
public static void main(String[] args){
System.out.println("count1=" + Test.count1);
System.out.println("count2=" + Test.count2);
}
}这里我给大家总结一个结论啊:永远不要给一个静态变量赋值默认的初始值,例如step3
private static int count2 = 0; //step 3
你这样倒是可以的
private static int count2 = 3; //step 3
0是默认的初始值,没有必要再 = 0 这样写,这样写有可能覆盖了初始化时赋的值,如例题那样,如果你赋值
= 3 ,你可能是有意要赋值为3,这是你有意覆盖的,这样还有些可接受。
我是这样得出的结论,而且我记得:在eclipse中如果例题这样写程序,在step3 处会用黄色标注警告信息,我感觉就是我分析的这个原因,大家认为呢?
我目测,这道题绝对不是招聘码奴级别程序员的,应该是一个大公司招聘高级java程序员的题目,如果这道题出的如我修改的那样,这道题才是考到点子上了。
这就是那类让码奴咒骂出题者的题,他们会非常气愤:“我不思考这些程序细节,我就是能写好程序不行啊!”
楼主可不可以爆一下,这套题的面试目标应聘者的薪金范围是不是在8k~15k之间?你研究的越深入,你的身价也越高,这是码奴们及其反感的事。
码奴时我们每个程序员都要经过的一段道路,但是有些人(大部分)就停止了码奴的级别不肯进取了。这样不好,为了摆脱码奴的身份,尽量把所有能考虑的细节都去思考一番,绝不整天在论坛抱怨公司,设想如何在30岁前转行。
说的有点离题了啊,就是最近面试应聘者的那些问题太简单了,还有些人大大抱怨太难,我的那些都根本没有这个1%难。
public Test(){ ...
构造器是公有的。
这道题考察的是:是否知道一个类加载时静态变量的初始化过程,其中还加入了一个对象实例化的影响,因为一个类加载时先把静态变量赋值为默认值,然后再初始化赋值,在赋值时又有一个对象被实例化了,构造器有影响了初始化值,最后 count2 = 0;又把构造器对count2的影响给抹掉了。所以考察的是类加载时静态变量的初始化过程。
count1++;
count2++;
System.out.println("" + count1 + count2);
public static void main(String[] args){
new Test().getTester();
}
private static Test tester = new Test(); //step 1
private static int count1; //step 2
private static int count2 = 0; //step 3
public Test(){ //step 4
count1++;
count2++;
System.out.println("" + count1 + count2);
}小弟还有一点不是很懂,执行count1++,这时候如果step2没有声明的话那就应该没有count1这个变量,所以就应该先执行了step2,所以我认为是不是这样的顺序--1234,然后count2的赋值是没有执行的,只有声明,执行构造方法后然后才赋值的呢???请有空的高手指点下。。
这时初始化完毕,开始由上向下进行赋值操作,一楼问的问题也由这个时间点开始,因此为tester赋值了new Test(); 因此触发了test()构造函数的执行,这时执行了count1++,count2++,根据初始化的结果,执行完后,count1 = 1,count2=1,因此打印出来的结果就是11;
然后继续向下赋值,因为count1没有赋值操作,因此结果还是1,而count2有赋值操作,因此java使用了1这个赋值操作为count2赋值;然后就是main中写的Test.getTester()方法的执行了.
因此最后执行顺序为:14235!
JVM 加载步骤,1、装载 2、连接 3、初始化
那么类成员默认值是什么时候设置的呢? 在连接阶段(这个阶段是不执行任何java代码的)。
各类型的成员的初始值大家都知道的。
然后就是初始化,顺序执行!
所以14235的执行顺序是正解。补充,执行 4 时, 2,3还未执行,但已经有初始值(连接操作时)。
所以输出一直是 1 1