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. MySQL 事务一览

    MySQL 中的事务? 对 MySQL 来说,事务通常是一组包含对数据库操作的集合.在执行时,只有在该组内的事务都执行成功,这个事务才算执行成功,否则就算失败.MySQL 中,事务支持是在引擎层实现的 ...

  2. CNN-4: GoogLeNet 卷积神经网络模型

    1.GoogLeNet 模型简介 GoogLeNet 是2014年Christian Szegedy提出的一种全新的深度学习结构,该模型获得了ImageNet挑战赛的冠军. 2.GoogLeNet 模 ...

  3. Linux中查找最耗CPU的Java代码问题

    第一步: 查看消耗CPU最高的进程PID [lolaage@web2 tomcat-ns]$ top top - 13:23:32 up 42 days, 19:11,  3 users,  load ...

  4. js实现——鼠标移动时跟随着一连的小图片

    首先放置一连的image <body> <div><img src="yezi.png" alt="tu"></div ...

  5. os路径

    import os linux下 例如: 我现在在 /home/settings.py文件下 # 获取当前的绝对路径 os.path.abspath(__file__) # 获取的内容 /home/s ...

  6. gdb调试命令总结

    常用命令: l 列出源代码 每次默认列10行 list 行号   列出从第几行开始的源代码 list函数名     列出某个函数的源代码 r    运行程序 next(或n)     执行下一行语句 ...

  7. S03_CH12_基于UDP的QSPI Flash bin文件网络烧写

    S03_CH12_基于UDP的QSPI Flash bin文件网络烧写 12.1概述 为了满足不同的需求,本例程在"基于TCP的QSPI Flash bin文件网络烧写"上进行修改 ...

  8. Codeforces 1245 D. Shichikuji and Power Grid

    传送门 经典的最小生成树模型 建一个点 $0$ ,向所有其他点 $x$ 连一条边权为 $c[x]$ 的边,其他任意两点之间连边,边权为 $(k_i+k_j)(\left | x_i-x_j\right ...

  9. Intercity Travelling CodeForces - 1009E (组合计数)

    大意: 有一段$n$千米的路, 每一次走$1$千米, 每走完一次可以休息一次, 每连续走$x$次, 消耗$a[1]+...+a[x]$的能量. 休息随机, 求消耗能量的期望$\times 2^{n-1 ...

  10. SVM的概率输出(Platt scaling)

    SVM的概率输出(Platt scaling) 2015-10-22 10:38:19 闲渔Love吉他 阅读数 8121 文章标签: Platt Scaling Calibr 更多 分类专栏: 计算 ...