java 类的域_Java类中对象域的初始化

java中,一个类的域(或者说类的属性,类的数据成员)可以是基本数据类型,也可以是对象的引用。对象域如果没有被初始化,会被置为null,如果在置为null的引用上调用方法,我们就会得到一个运行时错误。

在恰当的时间,恰当的位置,正确地初始化对象域是很重要的。

java中可以在四个位置进行类的对象域初始化:

在域定义时初始化

在类构造器中初始化

在使用类中的对象域之前手动初始化(这被称作懒惰初始化)

使用实例初始化块(常用于匿名内部类的初始化)

要注意上面列出的顺序并不是这些位置初始化的时间顺序。我们经常能看到的初始化方式是1和2。

当然,我们不能忘了一个特殊的存在:静态成员。

如果一个对象域是静态的,那么它的初始化就和类对象的初始化剥离开了。

静态成员的初始化在类被加载时进行,这是我们一定要知道的,但不是这篇文章的重点。

下面通过代码来证明这四种初始化发生的时间顺序。

类A拥有一个静态数据成员sstrA,和一个数据成员strA。拥有一个静态初始化块,和一个类初始化块。有一个无参构造函数。override了toString方法,在toString方法中懒惰初始化strA。

而类B结构与A基本相同,并且继承自A。

class A {

static String sstrA = "static string in A";

String strA = "string in A"; //在定义时初始化

static { //静态初始化块

System.out.println("A static init block start");

sstrA = "sstrA from init block";

}

{ //实例初始化块

System.out.println("instance init block start");

strA = "strA from init block";

}

public A() { //构造函数中可以做初始化

System.out.println("constructor start");

}

@Override

public String toString() {

if (strA == null) //这里使用了懒惰初始化

strA = "strA from delayed init";

return "static sstrA: " + sstrA + "\nstrA: " + strA;

}

}

class B extends A {

static String sstrB = "static string in B";

String strB = "string in B";

static {

System.out.println("B static init block start");

sstrB = "sstrB from init block";

}

{

System.out.println("instance init block start");

strB = "strB from init block";

}

public B() {

System.out.println("constructor start");

}

@Override

public String toString() {

if (strB == null)

strB = "strB from delayed init";

return super.toString() + "\nstatic sstrB: " + sstrB + "\nstrA: " + strB;

}

}

在main函数中创建这两个类的实例。

A a = new A();

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

System.out.println(a);

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

B b = new B();

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

System.out.println(b);

A static init block start

A instance init block start

A constructor start

----------------

static sstrA: sstrA from init block

strA: strA from init block

================

B static init block start

A instance init block start

A constructor start

B instance init block start

B constructor start

----------------

static sstrA: sstrA from init block

strA: strA from init block

static sstrB: sstrB from init block

strA: strB from init block

根据前半部分的运行结果,我们看到首先在类加载时,静态初始化块被执行了。

然后便是类实例化创建对象的过程,在构造函数被调用前,实例初始化块被首先执行。

根据toString的返回字符串,我们看到显示的内容是实例初始化块中赋值的字符串,说明最一开始在定义处初始化的字符串被实例初始化块覆盖掉。

最终得出一个顺序:

在最一开始,类被加载时,静态相关的初始化会执行

类实例化的第一步,定义处的初始化会被执行

然后是实例初始化块的执行

再后面才是构造器

最后当然是懒惰初始化在必要时得到执行

然后后半部分B类的实例化过程展现了继承存在时初始化的顺序。

因为A类在之前已经被加载过,所以静态初始化块不会被执行,此处只有B类的静态初始化块。

在实例化过程中首先会进行父类A的初始化,然后才是B本身的初始化。

总的来说,java在类成员初始化的顺序上,并没有什么反直觉的地方,只要稍加理解便能掌握。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值