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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 fantacyleo 于 2015-3-14 23:54 编辑

初始化对象时,静态/实例初始化代码块、静态/实例变量定义、构造函数的执行顺序是论坛上常见的讨论话题。我发现大家普遍认为它们之间有固定的执行顺序,通常是:静态初始化块-静态变量-实例初始化块-实例变量-构造函数 我不知道这样的观念来自何处,印象里老毕视频没有这样说过,有帖子提到国产教材云云。不幸的是,这种观点是错误的。如果它们之间有固定的执行顺序,那么如下两段代码的输出结果应该一模一样:
  1. public class Test {
  2. {
  3.                 System.out.println("initialization block");
  4.         }

  5.         String str = printStr();
  6.         
  7.         static String printStr() {
  8.                 System.out.println("printStr");
  9.                 return "str";
  10.         }
  11.         public static void main(String[] args){
  12.                 new Test();
  13.         }
  14. }
复制代码


  1. public class Test {
  2.         String str = printStr();
  3.         {
  4.                 System.out.println("initialization block");
  5.         }

  6.         
  7.         static String printStr() {
  8.                 System.out.println("printStr");
  9.                 return "str";
  10.         }
  11.         public static void main(String[] args){
  12.                 new Test();
  13.         }
  14. }
复制代码

但是,大家只要运行一下就会发现,两段代码的输出顺序恰好相反。这就证伪了“固定顺序说”。

那么,正确的初始化顺序到底是什么样的呢?下面我将引用Java语言最权威(没有之一)的参考文档:The Java Language Specification,作出3点归纳:

1. 静态成员的初始化(包括静态变量和静态初始化块)先于其他内容的初始化。这一点大家应该都没什么问题。
2. 静态变量和静态初始化块的初始化顺序由二者在代码中的出现顺序决定。类似地,实例变量和实例初始化块的初始化顺序由二者在代码中的出现顺序决定。The Java Language Specification的原话是:
Initialization consists of execution of any class variable initializers and static initializers of the class, in textual order.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class

我在上面给出的代码例子验证了实例变量和实例初始化块的初始化顺序由二者在代码中的出现顺序决定,静态变量和静态初始化块的顺序

3. 实例初始化块和实例变量定义优先于大多数而非全部构造函数代码。因为构造函数中调用父类构造函数的代码是优先于构造代码块和成员变量定义执行的。比如下面这段代码:
  1. public class Test {

  2.         public static void main(String[] args){
  3.                 new B();
  4.         }
  5. }

  6. class A {
  7.         public A() {
  8.                 System.out.println("A's constructor");
  9.         }
  10.         
  11. }

  12. class B extends A {
  13.         {
  14.                 System.out.println("B's initialization block");
  15.         }
  16.         
  17.         public B() {
  18.                 System.out.println("B's constructor");
  19.         }
  20.         
  21. }
复制代码

输出结果是:
A's constructor
B's initialization block
B's constructor

好,先说这么多,不足和错误之处恳请大家批评指出。祝大家的黑马梦早日实现!
PS
1. 类加载会使得对象初始化顺序变得更复杂,过段时间我将另帖说明。
2. 有意报黑马上海首期班的同学可加Q群:302602799

5 个回复

倒序浏览
w239983684 来自手机 中级黑马 2015-2-28 21:40:34
沙发
楼主总结得不错。
回复 使用道具 举报
请问上海黑马有安卓班吗?是不是还得绕一圈走流程?
回复 使用道具 举报
张思语 发表于 2015-2-28 22:40
请问上海黑马有安卓班吗?是不是还得绕一圈走流程?

5月18日的66期安卓班就是上海首期黑马呀,流程是一样的,不过有学费减3000优惠
回复 使用道具 举报
一直以为代码块先于其它非静态代码先加载
回复 使用道具 举报
受教了。。。。。。。。。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马