`

一道面试题引发的思考之:类的初始化

阅读更多

本人曾写过JAVA基础方面的blog,也是针对类的初始化的,不过那还只是对thinking in java中示例的调试及部分结论。如下
http://blog.csdn.net/luweifeng1983/archive/2008/01/09/2031662.aspx
不过最近看到一道csdn上的面试题却也没有很好的完成,说明自己在理解类的初始化方面还不够。。下面是贴子,有高人已经给出了很好的结论。。我在这里仅以借鉴做个人总结。。
http://topic.csdn.net/u/20081228/13/9b79175d-30fd-450b-9196-5c73af46b17b.html
试题如下:

packagecom.huogongqiang.bean;

 

publicclassTestinitial{

 

publicstaticvoidmain(String[]args){

inta=Test2.a;

System.out.println("finallymain");

}

 

static{

System.out.println("testinitalinitial");

}

}

 

classTest1{

 

staticinta=(int)Math.random()*5;

 

static{

System.out.println("test1inital");

}

}

 

classTest2extendsTest1{

staticintb=(int)Math.random()*10;

 

static{

System.out.println("test2inital");

}

}

输出结果为:
testinital initial
test1 inital
finally main

在这里我的主要疑问是为什么没有输出test2inital,在帖子中得到了很好的回答。。把主要的部结发布如下:
1、类的初始化是指初始化静态成员和静态块;
2、初始化一个类的时候首先初始化该类的父类,如果该类还有父类,那么先初始化父类的父类;
3、对于由引用类变量(class field)所引发的初始化,只会初始化真正定义该field的class。
4、如果一个static field是编译时常量(compile-time constant),则对它的引用不会引起定义它的类的初始化。

该程序首先加载main方法所在的类即
Testinitial类,发现该类有static块(这里如果有static成员则也会初始化),所以先输出testinital initial
程序执行到inta=Test2.a;这时候按我原来的想法是先初始化Test1,再初始化Test2的,但按上面的第3条:由引用类型Test2引发的初始化,只初始化真正定义该属性a的类即Test1类。所以输出test1 inital
最后输出finally main

这里针对第4点举例测试:如把Test1类中的staticinta=(int)Math.random()*5;改为static final int a = 5;

publicclassTest{

 

publicstaticvoidmain(String[]args){

inta=Test2.a;

System.out.println("finallymain");

}

 

static{

System.out.println("testinitalinitial");

}

}

 

classTest1{

 

 

staticfinalinta=5;

 

static{

System.out.println("test1inital");

}

}

 

classTest2extendsTest1{

staticintb=(int)Math.random()*10;

 

static{

System.out.println("test2inital");

}

}

这样输出结果为:
testinital initial
finally main

注意的是:如果是改成static int a = 5;则Test1还是会初始化的,因为
static int a = 5;并不是声明为常量

对于以上注意的第1,2点与我之前blog中测试的是一致的,如下例:

packagecom.gobusiness.eus.util;

 

publicclassTest{

 

publicstaticvoidmain(String[]args){

inta=Test2.a;

System.out.println("finallymain");

}

staticTest2t1=newTest2();

static{

System.out.println("testinitalinitial");

}

}

 

classTest1{

 

staticinta=(int)Math.random()*5;

 

 

static{

System.out.println("test1inital");

}

}

 

classTest2extendsTest1{

staticintb=(int)Math.random()*10;

 

static{

System.out.println("test2inital");

}

}

即我加入了staticTest2t1=newTest2(); 那么结果会怎么样呢?
Test加载后发现staticTest2t1=newTest2();这里因为Test2继承了Test1所以按第2点先初始化Test1类,于是结果为
test1 inital
test2 inital
testinital initial
finally main

对于类的初始化,帖子中有人这样答复:

  1. 一个类被初始化,归纳起来,大致有:
  2. 1)它的子类要初始化了,它作为祖先类,被装入并初始化.
  3. 2)创建它的对象,因而先要进行类的初始化.
  4. 3)对它的非final型的static成员(数据成员使用或赋值,方法成员调用),被装入并初始化.
  5. 4)对它的finalstatic型常量(且编译时值已知)的使用,会装入该类但不会被初始化
  6. 否则:即它的finalstatic型常量(且编译时值未知)的使用,会装入该类且会被初始化
  7. 5)其它操作(如:反射或Class.forName(...)等等..)

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics