java初始化时执行顺序,Java初始化执行顺序

本文详细探讨了Java中类的成员初始化顺序,包括构造函数、构造代码块、静态代码块以及在继承关系下的执行顺序。通过示例代码解析了类加载、对象创建过程中的初始化步骤,帮助理解Java内存管理和类的生命周期。
摘要由CSDN通过智能技术生成

前言

关于Java类的成员初始化顺序,一直是笔试中常见的基础考题,今天就执行顺序写一篇博文

主要从:构造函数,构造代码块,静态代码块,继承关系分析

构造函数

public A(){

//构造函数 to do something

}

对象新建时,调用对应的构造函数

构造函数的作用是用于给对象进行初始化

一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次

构造代码块

{

//构造代码块 to do something

}

public class InitTest {

static int i = 2;

{

i *= 2;

}

public InitTest(){

System.out.println("构造函数:" + i);

}

public static void main(String[] args) {

System.out.println(i);

InitTest test = new InitTest();

System.out.println(i);

}

{

i *= 3;

}

}

运行结果:

2

构造函数:12

12

构造代码块是在对象创建的时候执行的,如果没有创建对象不会执行构造代码块,而且构造代码块执行顺序先于构造函数的执行顺序。

构造代码块的作用是给对象进行初始化

构造代码块与构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,构造函数可以多次调用,而构造代码块第一次创建对象就会调用,而且仅一次

静态代码块

public class InitTest {

static int i = 2;

static{

i *= 2;

}

public static void main(String[] args) {

System.out.println(i);

}

static{

i *= 3;

}

}

结果:

12

静态代码块随着类的加载而执行,只执行一次,并且优先于主函数。具体说,静态代码块是由类调用的。类调用时,先执行静态代码块,然后才执行主函数的。

静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。

单个类中例子

public class InitTest {

InitTest() {

System.out.println("构造函数");

}

{

System.out.println("构造代码块");

}

static {

System.out.println("静态代码块");

}

public static void main(String[] args) {

InitTest test1 = new InitTest();

InitTest test2 = new InitTest();

}

}

结果:

静态代码块

构造代码块

构造函数

构造代码块

构造函数

结论:执行顺序从先到后为: 静态变量->静态代码块->变量->构造代码块-> 构造函数

继承中的初始化顺序

父类:

package com.hq.initTest;

/**

* 父类

*@author Huangqing

*@date 2018/6/27 15:54

*/

public class A {

static {

System.out.println("父类:静态代码块");

}

{

System.out.println("父类: 构造代码块");

}

public A(){

System.out.println("父类:构造函数");

}

private static String staticParentString = staticInitParent();

private String parentString = initParent();

public static String staticInitParent(){

System.out.println("父类:静态方法,被静态成员变量赋值调用");

return "staticInitParent";

}

public String initParent() {

System.out.println("父类:普通成员方法,被普通成员变量赋值调用");

return "initParent";

}

}

子类:

package com.hq.initTest;

/**

* 子类

*@author Huangqing

*@date 2018/6/27 15:54

*/

public class B extends A {

private static String staticChildString = staticInitChild();

private String childString = initChild();

static {

System.out.println("子类:静态代码块");

}

{

System.out.println("子类: 构造代码块");

}

public B(){

System.out.println("子类:构造函数");

}

public static String staticInitChild(){

System.out.println("子类:静态方法,被静态成员变量赋值调用");

return "staticInitParent";

}

public String initChild() {

System.out.println("子类:普通成员方法,被普通成员变量赋值调用");

return "initParent";

}

}

主方法:

package com.hq.initTest;

/**

* 测试Java类的成员和初始化块(代码块)初始化顺序

*@author Huangqing

*@date 2018/6/27 15:53

*/

public class InitTest {

public static void main(String[] args) {

System.out.println("主函数执行开始");

new B();

System.out.println("主函数执行结束");

}

}

运行结果:

主函数执行开始

父类:静态代码块

父类:静态方法,被静态成员变量赋值调用

子类:静态方法,被静态成员变量赋值调用

子类:静态代码块

父类: 构造代码块

父类:普通成员方法,被普通成员变量赋值调用

父类:构造函数

子类:普通成员方法,被普通成员变量赋值调用

子类: 构造代码块

子类:构造函数

主函数执行结束

经测试,得到在继承关系中,父类和子类成员初始化执行顺序结论:

1.父类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。

2.子类【静态成员】和【静态代码块】,按在代码中出现的顺序依次执行。

3.父类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行。

4.执行父类的构造方法。

5.子类的【普通成员变量被普通成员方法赋值】和【普通代码块】,按在代码中出现的顺序依次执行。

6.执行子类的构造方法。

附上一道阿里的Java初始化执行顺序题

public class TestConstructOrder {

public static int k = 0;

public static int k1;

public int k2;

public static TestConstructOrder t1 = new TestConstructOrder("t1");

public static TestConstructOrder t2 = new TestConstructOrder("t2");

public static int i = print("i");

public static int n = 99;

public int j = print("j");

{

print("构造块");

}

static {

print("静态块");

}

public TestConstructOrder(String str) {

System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);

++i;

++n;

}

public static int print(String str) {

System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);

++n;

return ++i;

}

/**

*

*/

public static void main(String[] args) {

TestConstructOrder t = new TestConstructOrder("init");

}

}

结果是:

1:j i=0 n=0

2:构造块 i=1 n=1

3:t1 i=2 n=2

4:j i=3 n=3

5:构造块 i=4 n=4

6:t2 i=5 n=5

7:i i=6 n=6

8:静态块 i=7 n=99

9:j i=8 n=100

10:构造块 i=9 n=101

11:init i=10 n=102

整个的执行步骤:(下面的分析不包括父类内容)

加载类信息:

1、静态变量默认初始化

2、对静态变量赋值,加载静态代码块中内容 (赋值顺序按书写顺序)

创建对象:

1、实例变量初始化

2、实例变量赋值(依然按顺序)

3、构造代码块中内容

4、构造函数中内容

分析:

1、 首先Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象。

2、加载类信息,对静态变量默认初始化,此时并未赋值(初始化顺序与代码顺序无关,具体可能要研究JVM虚拟机)

public static int k // 初始化, k = 0

public static int k1; // 初始化,k1 = 0

public static TestConstructOrder t1 = null // 初始化类 t1, t1 = null

public static TestConstructOrder t2 = null // 初始化类 t2, t2 = null

public static int i // 初始化 i = 0

public static int n = 99; // 初始化 n = 0

3、对静态变量赋值,加载静态代码块中内容。

k = 0 // k赋值0

t1 = new TestConstructOrder (“t1”) // 这里创建一个对象

注意 这里因为要创建对象,所以会执行创建对象的步骤:

实例变量初始化:

public int k2;// 初始化k2 , k2 = 0

public int j; // 初始化j, j = 0

实例变量赋值:

j = print(“j”) // 会执行静态方法

打印结果:1:j i = 0 n = 0

因为在创建对象,而我们前面说过,在创建对象时,构造代码块先于构造函数执行,所以会执行构造代码块

打印结果:2:构造块 i = 1 n = 1

然后执行构造函数

打印结果:3:t1 i = 2 n = 2

同样的,给t2赋值也会跟t1一样

打印结果:

4:j i = 3 n = 3

5:构造快 i = 4 n = 4

6:t2 i = 5 n = 5

继续赋值:i = print(“i”)

打印结果:

7:i i = 6 n = 6

对n赋值:int n = 99 // 此时 n = 99

然后执行静态代码块

打印结果:

8:静态块 i = 7 n = 99

最后:执行主函数,新建对象,这里的初始化顺序不再多说了,跟t1的相同

打印结果:

9:j i = 8 n = 100

10:构造快 i = 9 n = 101

6:init i = 10 n = 102

相信这道题,已经足够让你了解Java类成员的初始化顺序,博主也是一开始被弄糊涂了,如果还有不明白的地方,欢迎留言。如果觉得写得不错,别忘了给点个赞~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值