黑马程序员技术交流社区
标题: 类的初始化顺序 [打印本页]
作者: 秦冲 时间: 2012-5-29 19:15
标题: 类的初始化顺序
不调试 还真不好理解,看着顺序慢慢分析,各位能解释下吗?- 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...strings ){
-
- }
- }
- 输出结果:
- 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
复制代码问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?
作者: 杨永峰 时间: 2012-5-29 21:33
楼主的给出的代码很是犀利啊,根据对例子程序代码的运行,分析,我得出如下感悟,仅供参考:
类装载器在装载类的过程中,有一项工作是准备:给类的静态变量分配并初始化存储空间,这里的初始化存储空间应该是给静态变量赋予默认值。
类的装载完成后,才开始正式初始化,对于静态代码块和静态变量的初始化顺序,是和他们在程序中书写的前后顺序一致的。将静态代码块提到最前面测试:- public class Test2 {
- static{
- print("静态块"); /// 提到前面,先初始化,此时 i,n 均未进行定义值的初始化,所以输出的是默认值0。
- }
- public static int k=0;
- public static Test2 t1=new Test2("t1");
- public static Test2 t2=new Test2("t2");
- public static int i=print("i");
- public static int n=99;
-
- public int j=print("j");
-
- {
- print("构造块");
- }
-
- public Test2(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[] strings ){
-
- }
- }
复制代码 结果:- 1:静态块 i=0 n=0
- 1:j i=1 n=1
- 2:构造块 i=2 n=2
- 3:t1 i=3 n=3
- 4:j i=4 n=4
- 5:构造块 i=5 n=5
- 6:t2 i=6 n=6
- 7:i i=7 n=7
复制代码 下面执行到 public static Test1 t1 = new Test1("t1");由于定义的静态变量 t1 是指向本类对象的引用,使得对象的初始化提前,和一般的类的初始化过程相去甚远。对象创建过程中,先默认值初始化成员变量,再定义值初始化成员变量,然后执行构造块,接着执行构造方法。对例子中的代码稍作 修改进行测试:- public class Test1 {
-
-
- public static int k=0;
- public static Test1 t2 = null; /// 说明不是 Test1 t2 导致对象初始化提前。
- public static Test1 t1 = new Test1("t1");
- public static int i = print("i");
- public static int n = 99;
-
- public int j=print("j");
- public int b = print_1("b"); /// 这里赋值需要调用非静态方法。
- public int a = 100; /// a 未来得及赋予 100 ,在 print_1中输出 默认值。
- {
- 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 int print_1(String str){ ///增加非静态方法,打印出的 a 为默认值:0.
- System.out.println((++k)+":"+str+" i="+i+" n="+n + " a=" +a);
- ++n;
- return ++i;
- }
-
- public static void main(String[] strings ){
-
- }
- }
复制代码 结果:- 1:j i=0 n=0
- 2:b i=1 n=1 a=0
- 3:构造块 i=2 n=2
- 4:t1 i=3 n=3
- 5:i i=4 n=4
- 6:静态块 i=5 n=99
复制代码 接下来安照正常的顺序,继续初始化其他静态变量,代码块,静态方法等等。
作者: 伊文龙 时间: 2012-5-29 22:08
java类在装载的时候分几个阶段,
首先是.class字节码文件被装载到JVM中,在堆内存中为类的对象分配内存空间
然后就是java类的连接阶段,连接的时候有三个阶段。1:验证,2:准备,在这一阶段JVM会为类变量分配内存,并设置默认初始值,这一阶段不执行java代码。3:解析阶段。
最后才是对变量的实际初始化,这一阶段会为类的变量赋予真正的初始化值。而且是在首次主动使用该变量前才会初始化。
作者: 杨永峰 时间: 2012-5-30 11:44
我觉得该帖子应当 给分
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |