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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 秦冲 黑马帝   /  2012-5-29 19:15  /  2110 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

不调试 还真不好理解,看着顺序慢慢分析,各位能解释下吗?
  1. public class Test1 {
  2.      public static int k=0;
  3.      public static Test1 t1=new Test1("t1");
  4.      public static Test1 t2=new Test1("t2");
  5.      public static int i=print("i");
  6.      public static int n=99;
  7.    
  8.      public int j=print("j");
  9.    
  10.     {
  11.         print("构造块");
  12.      }
  13.    
  14.     static{
  15.        print("静态块");
  16.     }
  17.    
  18.    public Test1(String str){
  19.         System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
  20.         ++i;++n;
  21.    }
  22.    
  23.     public static int print(String str){
  24.          System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
  25.          ++n;
  26.           return ++i;
  27.     }
  28.    
  29.     public static void main(String...strings ){
  30.         
  31.   }
  32. }

  33. 输出结果:
  34. 1:j    i=0    n=0
  35. 2:构造块    i=1    n=1
  36. 3:t1    i=2    n=2
  37. 4:j    i=3    n=3
  38. 5:构造块    i=4    n=4
  39. 6:t2    i=5    n=5
  40. 7:i    i=6    n=6
  41. 8:静态块    i=7    n=99
复制代码
问题:i和n到底是什么时候声明的,public static Test1 t1=new Test1("t1");这句会去执行构造块和构造方法,但是这时候public static int i=print("i");并没执行,i是哪里出来的?它是按顺序先声明所有变量然后才从头再挨个赋值吗?

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1

查看全部评分

3 个回复

倒序浏览
楼主的给出的代码很是犀利啊,根据对例子程序代码的运行,分析,我得出如下感悟,仅供参考:

类装载器在装载类的过程中,有一项工作是准备:给类的静态变量分配并初始化存储空间,这里的初始化存储空间应该是给静态变量赋予默认值。
类的装载完成后,才开始正式初始化,对于静态代码块和静态变量的初始化顺序,是和他们在程序中书写的前后顺序一致的。将静态代码块提到最前面测试:
  1. public class Test2 {

  2.         static{
  3.        print("静态块"); /// 提到前面,先初始化,此时 i,n 均未进行定义值的初始化,所以输出的是默认值0。
  4.     }
  5.         public static int k=0;
  6.         public static Test2 t1=new Test2("t1");
  7.         public static Test2 t2=new Test2("t2");
  8.         public static int i=print("i");
  9.         public static int n=99;
  10.        
  11.         public int j=print("j");
  12.    
  13.     {
  14.         print("构造块");
  15.     }
  16.    
  17.     public Test2(String str){
  18.         System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
  19.         ++i;++n;
  20.     }
  21.    
  22.     public static int print(String str){
  23.          System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
  24.          ++n;
  25.           return ++i;
  26.     }
  27.    
  28.     public static void main(String[] strings ){
  29.         
  30.   }
  31. }
复制代码
结果:
  1. 1:静态块    i=0    n=0
  2. 1:j    i=1    n=1
  3. 2:构造块    i=2    n=2
  4. 3:t1    i=3    n=3
  5. 4:j    i=4    n=4
  6. 5:构造块    i=5    n=5
  7. 6:t2    i=6    n=6
  8. 7:i    i=7    n=7
复制代码
下面执行到 public static Test1 t1 = new Test1("t1");由于定义的静态变量 t1 是指向本类对象的引用,使得对象的初始化提前,和一般的类的初始化过程相去甚远。对象创建过程中,先默认值初始化成员变量,再定义值初始化成员变量,然后执行构造块,接着执行构造方法。对例子中的代码稍作 修改进行测试:
  1. public class Test1 {

  2.        
  3.        
  4.      public static int k=0;
  5.          public static Test1 t2 = null;  /// 说明不是 Test1 t2 导致对象初始化提前。
  6.      public static Test1 t1 = new Test1("t1");
  7.      public static int i = print("i");
  8.      public static int n = 99;
  9.          
  10.      public int j=print("j");
  11.          public int b = print_1("b"); /// 这里赋值需要调用非静态方法。
  12.          public int a = 100;          /// a 未来得及赋予 100 ,在 print_1中输出 默认值。
  13.     {
  14.         print("构造块");
  15.      }
  16.          
  17.         static{
  18.        
  19.        print("静态块");
  20.     }
  21.    
  22.    public Test1(String str){
  23.         System.out.println((++k)+":"+str+"    i="+i+"    n="+n);
  24.         ++i;++n;
  25.    }
  26.    
  27.     public static int print(String str){
  28.          System.out.println((++k)+":"+str+"    i="+i+"    n="+n );
  29.          ++n;
  30.           return ++i;
  31.     }
  32.        
  33.     public int print_1(String str){    ///增加非静态方法,打印出的 a 为默认值:0.
  34.          System.out.println((++k)+":"+str+"    i="+i+"    n="+n + "  a=" +a);
  35.          ++n;
  36.           return ++i;
  37.     }
  38.        
  39.     public static void main(String[] strings ){
  40.         
  41.   }
  42. }
复制代码
结果:
  1. 1:j    i=0    n=0
  2. 2:b    i=1    n=1  a=0
  3. 3:构造块    i=2    n=2
  4. 4:t1    i=3    n=3
  5. 5:i    i=4    n=4
  6. 6:静态块    i=5    n=99
复制代码
接下来安照正常的顺序,继续初始化其他静态变量,代码块,静态方法等等。



点评

同感  发表于 2012-5-29 22:45

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1

查看全部评分

回复 使用道具 举报
java类在装载的时候分几个阶段,
首先是.class字节码文件被装载到JVM中,在堆内存中为类的对象分配内存空间
然后就是java类的连接阶段,连接的时候有三个阶段。1:验证,2:准备,在这一阶段JVM会为类变量分配内存,并设置默认初始值,这一阶段不执行java代码。3:解析阶段。
最后才是对变量的实际初始化,这一阶段会为类的变量赋予真正的初始化值。而且是在首次主动使用该变量前才会初始化

点评

你这是整体上,非本题的讨论的重点。  发表于 2012-5-29 22:18
回复 使用道具 举报
我觉得该帖子应当 给分
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马