对于JAVA中类的初始化是一个很基础的问题,其中的一些问题也是易被学习者所忽略。当在编写代码的时候碰到时,常被这些问题引发的错误,感觉莫名其妙。而且现在许多大公司的面试题,对于这方面的考查也是屡试不爽。不管基于什么原因,我认为,对于java类中的初始化问题,有必要深入的了解。Java类的初始化,其实就是它在JVM的初始化问题(类加载的问题),对于它在JVM中的初始化是一个相当复杂的问题,是给专家们来探讨的,所以在这里我只是对一些容易忽略的问题,发表一下个人观点:
1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码:
- 01.class Test01...{
- 02. public Test01(int i)...{
- 03. System.out.println("Test01 of constractor : " + i);
- 04. }
- 05.}
- 06.public class Test02 ...{
- 07. private Test01 t1 = new Test01(1);
- 08. private int n = 10;
- 09.
- 10. public Test02()...{
- 11. System.out.println("Test02 of constructor : " + n);
- 12. }
- 13. private Test01 t2 = new Test01(2);
- 14. public static void main(String[] args) ...{
- 15. Test02 test = new Test02();
- 16. }
- 17.
- 18.}
- 19.输出的结果为:
- 20.Test01 of constractor : 1
- 21.Test01 of constractor : 2
- 22.Test02 of constructor : 10
复制代码 通过输出,可见当生成Test02的实例test时,它并不是首先调用其构造方法而是先是成员变量的初始化,而且成员的初始化的顺序以成员变量的定义顺序有关,先定义的先初始化,初始化后再调用构造方法。其实成员变量的初始化,在类的所有方法调用之前进行,包括构造方法
当类中有Static 修饰的成员呢?测试下面一段代码:- 01.public class Test03 ...{
- 02. private int i1 = printCommon();
- 03. private static int i2 = printStatic();
- 04.
- 05. public Test03()...{
- 06.
- 07. }
- 08. public static int printCommon()...{
- 09. System.out.println("i1 is init!");
- 10. return 1;
- 11. }
- 12. public static int printStatic()...{
- 13. System.out.println("i2 is init!");
- 14. return 2;
- 15. }
- 16. public static void main(String[] args) ...{
- 17. Test03 t = new Test03();
- 18. }
- 19.}
- 20.
- 21.输出结果为:
- 22.i2 is init!
- 23.i1 is init!
复制代码 可见static的成员比普通的成员变量先初始化。
我们都知道,如果一个类的成员变量没有在定义时,系统会给予系统默认的值,有=号的就直接给予右值,系统在给予初值和=号给予值这2中方式,在执行时间上有先后吗?为了测试,我编写了如下代码:- 01.public class Test04 ...{
- 02. private static Test04 t1 = new Test04();
- 03. private static int i1;
- 04. private static int i2 = 2;
- 05.
- 06. public Test04()...{
- 07. i1++;
- 08. i2++;
- 09. }
- 10.
- 11. public static void main(String[] args) ...{
- 12. Test04 t2 = new Test04();
- 13. System.out.println("t2.i1 = " + t2.i1);
- 14. System.out.println("t2.i2 = " + t2.i2);
- 15. }
- 16.}
- 17.我们先预计一下输出,可能有几种答案:2和3,3和3,2和2
- 18.执行代码后:
- 19.t2.i1 = 2
- 20.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的成员变量呢,其实我们在深入分析一个类的内部初始化后,对于存在父类的类的初始化其实原理都一样,具体以下面的代码为例:- 01.class SuperClass ...{
- 02. static...{
- 03. System.out.println("SuperClass of static block");
- 04. }
- 05.
- 06. public SuperClass()...{
- 07. System.out.println("SuperClass of constracutor");
- 08. }
- 09.}
- 10.
- 11.public class SubClass extends SuperClass...{
- 12. static...{
- 13. System.out.println("SubClass of static block");
- 14. }
- 15.
- 16. public SubClass()...{
- 17. System.out.println("SubClass of constracutor");
- 18. }
- 19.
- 20. public static void main(String[] args)...{
- 21. SuperClass t = new SubClass();
- 22. }
- 23.}
- 24.输出结果:
- 25.SuperClass of static block
- 26.SubClass of static block
- 27.SuperClass of constracutor
- 28.SubClass of constracutor
复制代码 可见当父类,和子类有Static时,先初始化Static,再初始化子类的Static,再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
父类上层还有父类时,总是先执行最顶层父类的Static-->派生类Static-->派生类Static-->.......-->子类Static-->顶层父类的其他成员变量-->父类构造方法--> 派生类的其他成员变量 --> 派生类构造方法--> ...............-->子类其他成员变量-->子类构造方法
|
|