java构造器初始化顺序_java中成员初始化与构造器初始化的顺序

1.初始化顺序

先看一个例子

class Counter {

int i;

Counter() {

//i = 7;

}

}

public class Test {

public static void main(String[] args) {

System.out.println(new Counter().i);

}

}我们执行这段程序,当i=7被注释掉,打印出0。这说明,成员变量(也就是Field)是有默认值的,int类型的默认值就是0。

当没有被注释掉,打印出的是7而不是0,可以看出自动初始化发生在构造器被调用之前。说明,想要构造器在堆中生成了一个对象,首先得保证这个对象中所有的成员变量都初始化过了,然后才能成功创建对象。

再看一个稍微复杂点的例子

public class OrderOfInitialization {

public static void main(String[] args) {

House h = new House();

h.f();

}

}

class Window {

Window(int marker) {

System.out.println("window(" + marker + ")");

}

}

class House {

Window w1 = new Window(1);

House() {

System.out.println("House()");

w3 = new Window(33);

}

Window w2 = new Window(2);

void f() {

System.out.println("f()");

}

Window w3 = new Window(3);

}

/*

* output:

window(1)

window(2)

window(3)

House()

window(33)

f()

*/通过结果可以得到结论:

1.变量定义的先后顺序决定了初始化顺序。

2.即使变量定义散布于构造方法定义之间,也是在构造器执行前进行初始化。

2.静态成员变量的初始化

1.静态成员变量是不依赖于对象的。无论创建多少对象,静态成员变量置占据一份存储区域,只会初始化一次。

2.类不是立即被加载的,只有用到的时候(比如创建对象或访问静态变量或静态方法)才会加载然后初始化静态成员变量,注意当访问编译期已确定的static final成员变量不会类加载,因为这种变量是编译期已知的常量。

注:static final int a = Random.nextInt(47) 这种虽然是static final修饰的变量,但是a的值运行期才可知所以并不是编译期常量。

3.当访问静态成员变量(非编译期可知的)或静态方法时。如果类还未初始化,需要对类中静态成员变量进行初始化。非静态成员变量是依赖于对象的,所以并不会涉及非静态成员的初始化。

4.当通过构造方法创建对象时,如果类已经初始化了,那么静态成员变量便不再初始化,只需要对非静态成员变量进行初始化。如果类还未初始化,静态与非静态的成员变量都会进行初始化。初始化顺序为静态先于非静态。等所有成员变量都已经初始化后,再执行构造方法,在堆中生成对象。(其实是类加载与创建对象两个过程)

根据以上四点来分析TIJ中的一个示例(p95)

class Bowl {

Bowl(int marker) {

System.out.println("Bowl(" + marker + ")");

}

void f1(int marker) {

System.out.println("f1(" + marker + ")");

}

}

class Table {

static Bowl bowl1 = new Bowl(1);

Table() {

System.out.println("Table()");

bowl2.f1(1);

}

void f2(int marker) {

System.out.println("f2(" + marker + ")");

}

static Bowl bowl2 = new Bowl(2);

}

class Cupboard {

Bowl bowl3 = new Bowl(3);

static Bowl bowl4 = new Bowl(4);

Cupboard() {

System.out.println("cupboard()");

bowl4.f1(2);

}

void f3(int marker) {

System.out.println("f3(" + marker + ")");

}

static Bowl bowl5 = new Bowl(5);

}

public class StaticInialization {

public static void main(String[] args) {

System.out.println("Creating new cupboard in main()");

new Cupboard();

System.out.println("Creating new cupboard in main()");

new Cupboard();

table.f2(1);

cupboard.f3(1);

}

static Table table = new Table();

static Cupboard cupboard = new Cupboard();

Bowl b = new Bowl(1); //自己额外添加的

}

先给出输出结果:

Bowl(1)

Bowl(2)

Table()

f1(1)

Bowl(4)

Bowl(5)

Bowl(3)

cupboard()

f1(2)

Creating new cupboard in main()

Bowl(3)

cupboard()

f1(2)

Creating new cupboard in main()

Bowl(3)

cupboard()

f1(2)

f2(1)

f3(1)

分析:

1.程序首先进入main方法,这是静态方法。所以得对StaticInitialization这个类加载,table与cupboard这两静态成员会进行初始化,而非静态成员b不会初始化。

2.table初始化:static Table table = new table(); 根据上文提到的第四点,table类中静态成员bowl1与bowl2先初始化,然后执行构造方法。

所以先打印出

Bowl(1)

Bowl(2)

Table()

f1(1)

3.cupboard初始化:static Cupboard cupboard = new Cupboard(); 根据上文提到的第四点,cupboard类中静态成员bowl4与bowl5先初始化,随后非静态成员bowl3初始化,最后执行构造方法。即输出:

Bowl(4)

Bowl(5)

Bowl(3)

cupboard()

f1(2)

4.StaticInitialization类初始化完成后进入main方法,打印一句Creating new cupboard in main(),随后到new Cupboard()这一句想要生成Cupboard对象。因为Cupboard类里静态变量已经初始化过了,所以只需对非静态成员变量bowl3初始化,最后执行构造方法。

输出:

Creating new cupboard in main()

Bowl(3)

cupboard()

f1(2)

5.程序继续往下执行,打印一句Creating new cupboard in main(),随后到new

Cupboard()这一句。过程与上一段相同。也是输出:

Creating new cupboard in main()

Bowl(3)

cupboard()

f1(2)

6.执行:table.f2(1);cupboard.f3(1);

输出:

f2(1)

f3(1)

3.代码块

当程序中出现代码块时,尽管看起来像是方法,但是其初始化过程与成员变量初始化过程是一样的。

静态代码块,在首次生成对象,或者首次访问类的静态成员变量或静态方法时执行一次。此后都不会再执行。

非静态代码块,每次生成新的对象时都会执行一次。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值