Java中程序初始化的顺序
1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码:
- 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 修饰的成员呢?测试下面一段代码:
- 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中方式,在执行时间上有先后吗?为了测试,我编写了如下代码:
- 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的成员变量呢,其实我们在深入分析一个类的内部初始化后,对于存在父类的类的初始化其实原理都一样,具体以下面的代码为例:
- 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();
初始化时调用父类的构造方法,是执行父类的原方法,还是执行子类中被重写的方法呢?
- 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初始化块之间的执行顺序是按照他们出现的先后顺序来执行的
- public class Test04
- {
- //下面的这两行代码放置的顺序,跟执行结果是有关系的
- private String t1 = test();
- {
- System.out.println("初始化快!");
- }
- //上面的这两行代码放置的顺序,跟执行结果是有关系的
- private String test(){
- System.out.println("实例变量的执行过程");
- return "test";
- }
- public Test04()
- {
- System.out.println("构造方法!");
- }
- public static void main(String[] args)
- {
- Test04 t2 = new Test04();
- }
- }
实例变量的执行过程
初始化快!
构造方法!
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(); } }
实例变量的执行过程
初始化快!
构造方法!
转载于:https://www.cnblogs.com/kexianting/p/8527553.html
Java中程序初始化的顺序相关推荐
- java 静态块初始化_简单了解java中静态初始化块的执行顺序
这篇文章主要介绍了简单了解java中静态初始化块的执行顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在java中,其应该是先于所有的方法执行. ...
- Java中对象的实例化顺序
文章目录 1 Java中对象的实例化顺序 1 Java中对象的实例化顺序 继承后的初始化顺序: 静态成员包括静态构造代码块,初始化顺序跟书写顺序有关.
- 浅谈 JAVA中静态初始化块和非静态初始化块的区别
众所周知在JAVA编程语言中有两种初始化块: 静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别 静态初始化块 定义: static{} 执 ...
- java中parent结构_详解java中继承关系类加载顺序问题
详解java中继承关系类加载顺序问题 实例代码: /** * Created by fei on 2017/5/31. */ public class SonClass extends ParentC ...
- Java中List初始化(亲测)
文章目录 文章目录 1.构造List后使用List.add初始化 2.使用 {undefined{}} 双括号语法 3.使用 Arrays.asList 4. 使用 Stream (JDK8) 5. ...
- java定义对象数组初始化_怎么定义对象数组 JAVA中怎么初始化对象数组?
java类怎样定义数组对象数组 在c++编程中,怎么定义对象数组的指针? JAVA中怎么初始化对象数组? java中怎么创建对象数组?比如我创建了一个学生类Sclass Student{ } 类中怎么 ...
- java项目包创建顺序_java程序初始化的顺序
来自:http://blog.csdn.net/socoolfj/article/details/750425 http://www.cnblogs.com/miniwiki/archive/20 ...
- java中程序执行顺序
①在java中执行顺序 一 静态初始化块 二 非静态初始化块 三 构造器 四 父类构造器 ② java中的赋值顺序 一 静态初始化块直接赋值 二 非静态初始化块直接赋值 三 父类继承的属性已赋值 四 ...
- java 初始化和清楚_浅谈Java中的初始化和清理
引言 这篇文章我们主要介绍Java初始化和清理的相关内容,这些内容虽然比较基础,但是还是在这边做一个简单的总结,方便以后查阅. 初始化过程 Java尽力保证:所有变量在使用之前都会得到恰当的初始化(对 ...
最新文章
- ustc小道消息20211216
- 添加别名_ssh别名免密登陆服务器
- KnockoutJS + My97DatePicker
- [js] 你有使用过pjax吗?它的原理是什么?
- 饭卡可以用水冲洗吗_薄壁不锈钢水管真的可以满足大众用水健康管道的要求吗?...
- RQNOJ36 数石子 并查集 简单应用
- 计算机二级考试c语言公共知识,2016年电大最新计算机二级考试c语言公共基础题知识点.doc...
- 简单Web服务器程序设计与实现
- 【MySQL】页面上查询时间与数据库中时间相差13个小时原因及解决办法
- 如何批量修改文件夹中的照片名称
- Vins_mono重力对齐理解
- 1小时紧急上线大屏?别怕,你还有即视
- 电阻系列知识(5)-电阻的阻值
- 为什么你需要企业架构一文,对企业架构在实施上的启示
- Java charAt() 方法
- 异动分析(四)利用Python计算指标贡献度
- Redis学习之基础知识
- android x11 ssh,用SSH实现X11转发
- Java中Double保留自定义小数位的几种方法
- AkelPad最新中文版