对于JAVA中类的初始化是一个很基础的问题,其中的一些问题也是易被学习者所忽略。当在编写代码的时候碰到时,常被这些问题引发的错误,感觉莫名其妙。而且现在许多大公司的面试题,对于这方面的考查也是屡试不爽。不管基于什么原因,我认为,对于java类中的初始化问题,有必要深入的了解。Java类的初始化,其实就是它在JVM的初始化问题(类加载的问题),对于它在JVM中的初始化是一个相当复杂的问题,是给专家们来探讨的,所以在这里我只是对一些容易忽略的问题,发表一下个人观点:
1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码:

[java] view plaincopyprint?
  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 staticvoid 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

class Test01...{ public Test01(int i)...{ System.out.println("Test01 of constractor : " + i); } } public class Test02 ...{ private Test01 t1 = new Test01(1); private int n = 10; public Test02()...{ System.out.println("Test02 of constructor : " + n); } private Test01 t2 = new Test01(2); public static void main(String[] args) ...{ Test02 test = new Test02(); } } 输出的结果为: Test01 of constractor : 1 Test01 of constractor : 2 Test02 of constructor : 10

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

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

public class Test03 ...{ private int i1 = printCommon(); private static int i2 = printStatic(); public Test03()...{ } public static int printCommon()...{ System.out.println("i1 is init!"); return 1; } public static int printStatic()...{ System.out.println("i2 is init!"); return 2; } public static void main(String[] args) ...{ Test03 t = new Test03(); } } 输出结果为: i2 is init! i1 is init!

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

[java] view plaincopyprint?
  1. public class Test04 ...{
  2. private static Test04 t1 =new Test04();
  3. private staticint i1;
  4. private staticint i2 = 2;
  5. public Test04()...{
  6. i1++;
  7. i2++;
  8. }
  9. public staticvoid 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

public class Test04 ...{ private static Test04 t1 = new Test04(); private static int i1; private static int i2 = 2; public Test04()...{ i1++; i2++; } public static void main(String[] args) ...{ Test04 t2 = new Test04(); System.out.println("t2.i1 = " + t2.i1); System.out.println("t2.i2 = " + t2.i2); } } 我们先预计一下输出,可能有几种答案:2和3,3和3,2和2 执行代码后: t2.i1 = 2 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的成员变量呢,其实我们在深入分析一个类的内部初始化后,对于存在父类的类的初始化其实原理都一样,具体以下面的代码为例:

[java] view plaincopyprint?
  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 SubClassextends 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 staticvoid 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

class SuperClass ...{ static...{ System.out.println("SuperClass of static block"); } public SuperClass()...{ System.out.println("SuperClass of constracutor"); } } public class SubClass extends SuperClass...{ static...{ System.out.println("SubClass of static block"); } public SubClass()...{ System.out.println("SubClass of constracutor"); } public static void main(String[] args)...{ SuperClass t = new SubClass(); } } 输出结果: SuperClass of static block SubClass of static block SuperClass of constracutor SubClass of constracutor

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

[java] view plaincopyprint?
  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 SubClassTestextends 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 staticvoid 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()方法!!并且还出现一个怪异的现象,子类的privteint 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 staticint 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 staticint k = getInt();
  58. public staticint 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 staticvoid 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 ----

class SuperClass...{ public SuperClass()...{ System.out.println("SuperClass of constructor"); m(); } public void m()...{ System.out.println("SuperClass.m()"); } } public class SubClassTest extends SuperClass ...{ private int i = 10; public SubClassTest()...{ System.out.println("SubClass of constructor"); super.m(); m(); } public void m()...{ System.out.println("SubClass.m(): i = " + i); } public static void main(String[] args)...{ SuperClass t = new SubClassTest(); } } 可能很多人会认为输出为: SuperClass of constructor SubClass.m(): i = 10 SubClass of constructor SuperClass.m() SubClass.m(): i = 10 其实不然! 正确输出为: SuperClass of constructor SubClass.m(): i = 0 SubClass of constructor SuperClass.m() SubClass.m(): i = 10 在生成对象时,父类调用的M()方法,不是父类的 M()方法,而时子类中被重写了的M()方法!!并且还出现一个怪异的现象,子类的privte int i 也被父类访问到,这不是和我们说private的成员只能在本类使用的原则相违背了吗?其实我们说的这条原则是编译期间所遵守的,在JAVA程序的编译期间,它只检查语法的合法性,在JAVA的JVM中,即运行期间,不管你声明的什么,对于JVM来说都是透明的,而多态是在运行期间执行的,所以能拿到SubClass的private成员,一点都不奇怪,只是此时还没执行 i = 10,所以在父类的构造方法中调用m()时,系统只能将i赋予系统初值0。 下面是我设计的一道完整的初始化例子,可测试你对类的初始化问题是否完整掌握: 写出程序运行的结果: class A...{ private int i = 9; protected static int j; static...{ System.out.println("-- Load First SuperClass of static block start!-- "); System.out.println("j = " + j); System.out.println("-- Load First SuperClass of static block End -- "); } public A()...{ System.out.println("------- Load SuperClass of structor start --------"); System.out.println("Frist print j = " + j); j = 10; m(); System.out.println("k = " + k); System.out.println("Second print j = " + j); System.out.println("----------- Load SuperClass End ----------- "); } private static int k = getInt(); public static int getInt()...{ System.out.println("Load SuperClass.getInt() "); return 11; } static...{ System.out.println("--- Load Second SuperClass of static block!-------"); System.out.println("j = " + j); System.out.println("k = " + k); System.out.println("-- Load Second SuperClass of static block End -- "); } public void m()...{ System.out.println("SuperClass.m() , " + "j = " +j); } } class B extends A ...{ private int a = 10; static...{ System.out.println("---- Load SubClass of static block!------"); System.out.println("-- Load SubClass of static block End -- "); } public B()...{ System.out.println("Load SubClass of structor"); m(); System.out.println("--- Load SubClass End ---- "); } public void m()...{ System.out.println("SubClass.m() ," + "a = " + a ); } } public class Test1...{ public static void main(String[] args)...{ A a = new B(); } } 正确的答案为: -- Load First SuperClass of static block start!-- j = 0 -- Load First SuperClass of static block End -- Load SuperClass.getInt() --- Load Second SuperClass of static block!------- j = 0 k = 11 -- Load Second SuperClass of static block End -- ---- Load SubClass of static block!------ -- Load SubClass of static block End -- ------- Load SuperClass of structor start -------- Frist print j = 0 SubClass.m() ,a = 0 k = 11 Second print j = 10 ----------- Load SuperClass End ----------- Load SubClass of structor SubClass.m() ,a = 10 --- Load SubClass End ----

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

[java] view plaincopyprint?
  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 staticvoid main(String[] args)
  18. {
  19. Test04 t2 = new Test04();
  20. }
  21. }
  22. 运行结果:
  23. 初始化快!
    实例变量的执行过程
    构造方法!

Java 类实例化顺序相关推荐

  1. 【知识总结】Java类初始化顺序说明

    微信公众号:努力编程的小猪 如有问题或建议,请公众号留言 Java类初始化顺序说明 一个类中包含如下几类东西,他们前后是有顺序关系的 静态属性:static 开头定义的属性 静态方法块: static ...

  2. (转)java类初始化顺序 - jackyrong的世界 - 博客园

    (转)java类初始化顺序 我们大家都知道,对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器.我们也可以通过 ...

  3. java类初始化顺序_Java 类的初始化顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次 构造代码块:类中直接用{}定义,每一次创建对象时执行 执行顺序优先级:静态块,main(),构造块,构造方法 1. 构造函数 publi ...

  4. Java提高篇——静态代码块、构造代码块、构造函数以及Java类初始化顺序

    构造函数 public HelloA(){//构造函数} 关于构造函数,以下几点要注意: 1.对象一建立,就会调用与之相应的构造函数,也就是说,不建立对象,构造函数时不会运行的. 2.构造函数的作用是 ...

  5. 面试题:Java类初始化顺序

    1. 问题来源 你遇到过哪些质量很高的 Java 面试? - ZO01的回答 - 知乎 https://www.zhihu.com/question/60949531/answer/579002882 ...

  6. Java类初始化顺序(变量赋值与静态代码块的执行时间)

    前言:最近写代码的时候经常见到见到static代码块,不由对static的执行时间产生了兴趣,进而对类初始化顺序产生了兴趣. 类从编译到执行的过程: 在使用ClassLoader将字节码转换为JVM中 ...

  7. 一文详解Java类初始化顺序

    目录 一.普通类 二.包含继承关系 三.包含接口.抽象类关系 本文将介绍三种情形下的类初始化顺序. 一.普通类 Java类:Animal.java package ztt.继承接口多态.执行顺序测试; ...

  8. JAVA类初始化顺序总结

    类的初始化 初始化顺序 首先来看下,当一个类从main入口方法,对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序: public class ClassLoadTest {priv ...

  9. 对Java类初始化顺序的一些理解

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次 构造代码块:类中直接用{}定义,每一次创建对象时执行. 执行顺序优先级:(静态块| 静态变量) , main(), (构造块|成员变量) ...

最新文章

  1. Linux shell 学习笔记(15)— shell 正则表达式
  2. 智能车竞赛计时系统感应线圈放在节能充电线圈上输出电压会多大?
  3. 数据中心系统管理员基础知识培训
  4. JZOJ 5399. 【NOIP2017提高A组模拟10.7】Confess
  5. Transformer升级之路:Sinusoidal位置编码追根溯源
  6. arm 指令1(转)
  7. JBoss BPM Travel Agency演示与现代BPM数据集成
  8. 精读linux源码,Linux基础入门的操作精读.doc
  9. [蛋蛋四格漫画]蛋蛋式按摩……(中日台词对照)
  10. python画spc控制图_手把手教你SPC控制图怎么做以及SPC控制图分类
  11. 最近公共祖先 解题报告
  12. 计算机操作系统(第四版)课后习题答案(第一章)
  13. labview 控件安装步骤
  14. 微信小程序从入门到放弃(五)
  15. heartbeat高可用详解
  16. 美丽心灵 A Beautiful Mind
  17. linux第一周总结
  18. Jmeter的元件使用介绍:前置处理器详解
  19. 【转】立方体的体对角线穿过多少个正方体?
  20. SQL的update语句

热门文章

  1. 富文本编辑器 vue-quill-editor使用(新增,展示,修改,添加附件相关)
  2. 云服务平台分类——IAAS,PAAS,SAAS
  3. DevOps-深入浅出详解
  4. 蓝桥杯 试题 算法训练 逗志芃的危机
  5. Jmeter-函数助手-随机函数的使用(模拟1000+个手机用户获取短信验证码)
  6. 爬取某电影网站排行榜TOP250
  7. 链表反转(指定区间)
  8. ERROR 1031 HY000 Table storage engine for xxx does not have this option
  9. 奥运五环python代码_python图形绘制奥运五环实例讲解
  10. 编程计算两个数的最大公约数