1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码:

  1. class Test01...{
  2. public Test01(int i)...{
  3. System.out.println("Test01 of constractor : " + i);
  4. }
  5. }
  6. public class Test02 ...{
  7. private Test01 t1 = new Test01(1);
  8. private int n = 10;
  9. public Test02()...{
  10. System.out.println("Test02 of constructor : " + n);
  11. }
  12. private Test01 t2 = new Test01(2);
  13. public static void main(String[] args) ...{
  14. Test02 test = new Test02();
  15. }
  16. }
  17. 输出的结果为:
  18. Test01 of constractor : 1
  19. Test01 of constractor : 2
  20. Test02 of constructor : 10

通过输出,可见当生成Test02的实例test时,它并不是首先调用其构造方法而是先是成员变量的初始化,而且成员的初始化的顺序以成员变量的定义顺序有关,先定义的先初始化,初始化后再调用构造方法。其实成员变量的初始化,在类的所有方法调用之前进行,包括构造方法
当类中有Static 修饰的成员呢?测试下面一段代码:

  1. public class Test03 ...{
  2. private int i1 = printCommon();
  3. private static int i2 = printStatic();
  4. public Test03()...{
  5. }
  6. public static int printCommon()...{
  7. System.out.println("i1 is init!");
  8. return 1;
  9. }
  10. public static int printStatic()...{
  11. System.out.println("i2 is init!");
  12. return 2;
  13. }
  14. public static void main(String[] args) ...{
  15. Test03 t = new Test03();
  16. }
  17. }
  18. 输出结果为:
  19. i2 is init!
  20. i1 is init!

可见static的成员比普通的成员变量先初始化。
我们都知道,如果一个类的成员变量没有在定义时,系统会给予系统默认的值,有=号的就直接给予右值,系统在给予初值和=号给予值这2中方式,在执行时间上有先后吗?为了测试,我编写了如下代码:

  1. public class Test04 ...{
  2. private static Test04 t1 = new Test04();
  3. private static int i1;
  4. private static int i2 = 2;
  5. public Test04()...{
  6. i1++;
  7. i2++;
  8. }
  9. public static void main(String[] args) ...{
  10. Test04 t2 = new Test04();
  11. System.out.println("t2.i1 = " + t2.i1);
  12. System.out.println("t2.i2 = " + t2.i2);
  13. }
  14. }
  15. 我们先预计一下输出,可能有几种答案:2和3,3和3,2和2
  16. 执行代码后:
  17. t2.i1 = 2
  18. t2.i2 = 3

为什么是2和3呢?其实代码的执行顺序是这样的:首先执行给t1,i1,i2分别给予初始值null,0,0,再执行
Test04 t1 =new Test04(),这样i1++,i2++被执行,i1,i2都变为1,执行完毕后接着执行int i1; i1,i2的值仍然是1,1,当执行int i2 = 2时i2被赋予了值,即i1 = 1,i2=2;再执行Test04 t2 = new Test04(),i1,i2再执行++,此时i1 =2,i2 =3,输出i1,i2,结果就是:t2.i1 = 2,t2.i2 = 3。 通过上面的代码我们可以认为系统默认值的给予比通过等号的赋予先执行。
2,一个类还有上层的类,即父类:
      当生成一个子类时,大家到知道会调用父类的构造方法。如果子类和父类中都有Static的成员变量呢,其实我们在深入分析一个类的内部初始化后,对于存在父类的类的初始化其实原理都一样,具体以下面的代码为例:

  1. class SuperClass ...{
  2. static...{
  3. System.out.println("SuperClass of static block");
  4. }
  5. public SuperClass()...{
  6. System.out.println("SuperClass of constracutor");
  7. }
  8. }
  9. public class SubClass extends SuperClass...{
  10. static...{
  11. System.out.println("SubClass of static block");
  12. }
  13. public SubClass()...{
  14. System.out.println("SubClass of constracutor");
  15. }
  16. public static void main(String[] args)...{
  17. SuperClass t = new SubClass();
  18. }
  19. }
  20. 输出结果:
  21. SuperClass of static block
  22. SubClass of static block
  23. SuperClass of constracutor
  24. SubClass of constracutor

可见当父类,和子类有Static时,先初始化Static,再初始化子类的Static,再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
父类上层还有父类时,总是先执行最顶层父类的Static-->派生类Static-->派生类Static-->.......-->子类Static-->顶层父类的其他成员变量-->父类构造方法--> 派生类的其他成员变量 --> 派生类构造方法--> ...............-->子类其他成员变量-->子类构造方法
讨论到继承,就不得提一下多态:
如果父类构造方法的代码中有子类中被重写得方法,当执行这样的语句
SuperClass super = new SubClass();
初始化时调用父类的构造方法,是执行父类的原方法,还是执行子类中被重写的方法呢?

  1. class SuperClass...{
  2. public SuperClass()...{
  3. System.out.println("SuperClass of constructor");
  4. m();
  5. }
  6. public void m()...{
  7. System.out.println("SuperClass.m()");
  8. }
  9. }
  10. public class SubClassTest extends SuperClass ...{
  11. private int i = 10;
  12. public SubClassTest()...{
  13. System.out.println("SubClass of constructor");
  14. super.m();
  15. m();
  16. }
  17. public void m()...{
  18. System.out.println("SubClass.m(): i = " + i);
  19. }
  20. public static void main(String[] args)...{
  21. SuperClass t = new SubClassTest();
  22. }
  23. }
  24. 可能很多人会认为输出为:
  25. SuperClass of constructor
  26. SubClass.m(): i = 10
  27. SubClass of constructor
  28. SuperClass.m()
  29. SubClass.m(): i = 10
  30. 其实不然!
  31. 正确输出为:
  32. SuperClass of constructor
  33. SubClass.m(): i = 0
  34. SubClass of constructor
  35. SuperClass.m()
  36. SubClass.m(): i = 10
  37. 在生成对象时,父类调用的M()方法,不是父类的 M()方法,而时子类中被重写了的M()方法!!并且还出现一个怪异的现象,子类的privte  int i 也被父类访问到,这不是和我们说private的成员只能在本类使用的原则相违背了吗?其实我们说的这条原则是编译期间所遵守的,在JAVA程序的编译期间,它只检查语法的合法性,在JAVA的JVM中,即运行期间,不管你声明的什么,对于JVM来说都是透明的,而多态是在运行期间执行的,所以能拿到SubClass的private成员,一点都不奇怪,只是此时还没执行 i = 10,所以在父类的构造方法中调用m()时,系统只能将i赋予系统初值0。
  38. 下面是我设计的一道完整的初始化例子,可测试你对类的初始化问题是否完整掌握:
  39. 写出程序运行的结果:
  40. class A...{
  41. private int i = 9;
  42. protected static int j;
  43. static...{
  44. System.out.println("-- Load First SuperClass of static block start!-- ");
  45. System.out.println("j = " + j);
  46. System.out.println("-- Load First SuperClass of static block End  -- ");
  47. }
  48. public A()...{
  49. System.out.println("------- Load SuperClass of structor start --------");
  50. System.out.println("Frist print j = " + j);
  51. j = 10;
  52. m();
  53. System.out.println("k = " + k);
  54. System.out.println("Second print j = " + j);
  55. System.out.println("-----------  Load  SuperClass End    ----------- ");
  56. }
  57. private static int k = getInt();
  58. public static int getInt()...{
  59. System.out.println("Load SuperClass.getInt() ");
  60. return 11;
  61. }
  62. static...{
  63. System.out.println("--- Load Second SuperClass of static block!-------");
  64. System.out.println("j = " + j);
  65. System.out.println("k = " + k);
  66. System.out.println("-- Load Second SuperClass of static block End -- ");
  67. }
  68. public void m()...{
  69. System.out.println("SuperClass.m() , " + "j = " +j);
  70. }
  71. }
  72. class B extends A ...{
  73. private  int a = 10;
  74. static...{
  75. System.out.println("---- Load SubClass of static block!------");
  76. System.out.println("-- Load SubClass of static block End -- ");
  77. }
  78. public B()...{
  79. System.out.println("Load SubClass of structor");
  80. m();
  81. System.out.println("---   Load SubClass End  ---- ");
  82. }
  83. public void m()...{
  84. System.out.println("SubClass.m() ," + "a = " + a );
  85. }
  86. }
  87. public class Test1...{
  88. public static void main(String[] args)...{
  89. A a = new B();
  90. }
  91. }
  92. 正确的答案为:
  93. -- Load First SuperClass of static block start!--
  94. j = 0
  95. -- Load First SuperClass of static block End  --
  96. Load SuperClass.getInt()
  97. --- Load Second SuperClass of static block!-------
  98. j = 0
  99. k = 11
  100. -- Load Second SuperClass of static block End --
  101. ---- Load SubClass of static block!------
  102. -- Load SubClass of static block End --
  103. ------- Load SuperClass of structor start --------
  104. Frist print j = 0
  105. SubClass.m() ,a = 0
  106. k = 11
  107. Second print j = 10
  108. -----------  Load  SuperClass End    -----------
  109. Load SubClass of structor
  110. SubClass.m() ,a = 10
  111. ---   Load SubClass End  ----

下面需要说明的一点也是至关重要的一点:那就是成员变量的初始化和非static初始化块之间的执行顺序是按照他们出现的先后顺序来执行的

    1. public class Test04
    2. {
    3. //下面的这两行代码放置的顺序,跟执行结果是有关系的
    4. private  String t1 = test();
    5. {
    6. System.out.println("初始化快!");
    7. }
    8. //上面的这两行代码放置的顺序,跟执行结果是有关系的
    9. private String test(){
    10. System.out.println("实例变量的执行过程");
    11. return "test";
    12. }
    13. public Test04()
    14. {
    15. System.out.println("构造方法!");
    16. }
    17. public static void main(String[] args)
    18. {
    19. Test04 t2 = new Test04();
    20. }
    21. }

  实例变量的执行过程

      初始化快!

      构造方法!

public class NonStaticBlock {
{
System.out.println("初始化快!");
}
//下面的这两行代码放置的顺序,跟执行结果是有关系的
private String t1 = test();
//上面的这两行代码放置的顺序,跟执行结果是有关系的 private String test(){
System.out.println("实例变量的执行过程");
return "test";
} public NonStaticBlock()
{
System.out.println("构造方法!");
} public static void main(String[] args)
{
NonStaticBlock t2 = new NonStaticBlock();
} }

初始化快!
实例变量的执行过程
构造方法!

public class NonStaticBlock {

    //下面的这两行代码放置的顺序,跟执行结果是有关系的
private String t1 = test();
//上面的这两行代码放置的顺序,跟执行结果是有关系的 private String test(){
System.out.println("实例变量的执行过程");
return "test";
} public NonStaticBlock()
{
System.out.println("构造方法!");
}
{
System.out.println("初始化快!");
}
public static void main(String[] args)
{
NonStaticBlock t2 = new NonStaticBlock();
} }

实例变量的执行过程
初始化快!
构造方法!

Java中程序初始化的顺序的更多相关文章

  1. Java程序初始化的顺序

    Java程序初始化的顺序 java程序初始化工作可以在许多不同的代码块中来完成(例如:静态代码块.构造函数等),他们执行的顺序如下: 父类静态变量 父类静态代码块 子类静态变量 子类静态代码块 父类非 ...

  2. 初步探究java中程序退出、GC垃圾回收时,socket tcp连接的行为

    初步探究java中程序退出.GC垃圾回收时,socket tcp连接的行为 今天在项目开发中需要用到socket tcp连接相关(作为tcp客户端),在思考中发觉需要理清socket主动.被动关闭时发 ...

  3. Java中的初始化详细解析

    今天所要详细讲解的是Java中的初始化,也就是new对象的过程中,其程序的行走流程. 先说没有静态成员变量和静态代码块的情况. public class NormalInit { public sta ...

  4. [转载]Java中异常的捕获顺序(多个catch)

    http://blog.sina.com.cn/s/blog_6b022bc60101cdbv.html [转载]Java中异常的捕获顺序(多个catch) (2012-11-05 09:47:28) ...

  5. java中的TreeMap如何顺序按照插入顺序排序

    java中的TreeMap如何顺序按照插入顺序排序 你可以使用LinkedHashMap  这个是可以记住插入顺序的. 用LinkedHashMap吧.它内部有一个链表,保持插入的顺序.迭代的时候,也 ...

  6. 浅谈Java中静态初始化块跟非初始化块

    众所周知在JAVA编程语言中有两种初始化块:   静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别   静态初始化块 定义:       ...

  7. 《Java程序员面试笔试宝典》之Java程序初始化的顺序是怎样的

    在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下三原则优 ...

  8. [java] java中的初始化顺序

    先看程序: package init_cls; class A{ {System.out.println("i am in the class A!");} static { Sy ...

  9. 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的

    在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象.    Java程序的初始化一般遵循以下三个原则(以下 ...

随机推荐

  1. 搭建一个超好用的 cmdb 系统

    10 分钟为你搭建一个超好用的 cmdb 系统 CMDB 是什么,作为 IT 工程师的你想必已经听说过了,或者已经烂熟了,容我再介绍一下,以防有读者还不知道.CMDB 的全称是 Configurati ...

  2. Java与计算机常识

    DB2   IBM公司的数据库 Oracle  Orcle的数据库 Mysql    数据库(免费) 1.  jetty    小型服务器(类似于tomcat) Jetty 是一个开源的servlet ...

  3. Python 中文件操作

    上代码: import os import os.path rootdir = "d:/code/su/data" # 指明被遍历的文件夹 for parent,dirnames, ...

  4. gin mongodb restful api设计: 动态的patch接口

    目录 什么是Patch? Patch方法可以用来更新资源的一个组成部分 什么时候使用Patch? 当你仅需更新资源的某一项,即不完全也不幂等 那当我们的模型在数据库中几乎每个字段都可能会遇到改变的时候 ...

  5. linux时间同步ntpdate

    1.安装ntpdate,执行以下命令 yum install ntpdate -y 2.手工同步网络时间,执行以下命令,将从time.nist.gov同步时间 ntpdate 0.asia.pool. ...

  6. mybaits实现oracle批量新增数据,回填主键

    项目有需求,百度了很久,反正他们说的方法,我都没成功,我也不知道是不是我写代码的姿势不正确,没办法只能自己想法子了 我们这个项目用到了通过Mapper,通用Mapper里通过OracleProvide ...

  7. (十六)Hibernate中的延迟加载

    一.什么是延迟加载 为了节省Hibernate加载对象的性能节销,在Hibernate中真正需要用到这个对象时,才会发出        SQL语句来抓取这个对象.这一个过程称为延迟加载. 二.延迟加载 ...

  8. (九)SpringBoot之错误处理

    一.错误处理方法 1.Spring Boot 将所有的错误默认映射到/error, 实现ErrorController 2.添加自定义的错误页面   二.Spring Boot 将所有的错误默认映射到 ...

  9. Flash播放控件属性详解

    Flash 播放控件属性详解 一.属性篇 1.AlignMode(读写)  语法:AlignMode As Long  说明:对齐方式(与SAlign 属性联动).当控件的长宽比例与影片不一致且WMo ...

  10. opengl 笔记

    1. 本函数可以禁用多边形正面或背面上的光照.阴影和颜色计算及操作,消除不必要的渲染计算是因为无论对象如何进行旋转或变换,都不会看到多边形的背面.用GL_CULL_FACE参数调用glEnable和g ...