《Java编程思想》读书笔记——构造器初始化顺序

Java尽力保证:所有变量在使用前都能得到恰当的初始化。对于局部变量,Java以编译时错误的形式来贯彻这种保证。

public static void main(String[] args) {
    int i;
    System.out.println(i++);
}

运行结果:
Error:(12, 28) java: 可能尚未初始化变量i

类的没有基本数据成员保证都会有一个初始值,即使数据成员并未显示赋初值。对于类中的对象引用来说,如果不将其初始化,此引用就会获得一个特殊值null。

public class Dog {
    public String name;
    public int age;
    public Dog son;
}

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog.name);
        System.out.println(++dog.age);
        System.out.println(dog.son);
    }
}

运行结果:
null
1
null

如果我们在定义类成员变量时没有为其定义初值,那么编译器就会自动为其加上初值。booleanfalseshortintlong0floatdouble0.0char0所以显示为空。

在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。

public class Window {
    public Window(){
        System.out.println("Window()");
    }
}

public class House {
    public Window win = new Window();
    public House(){
        System.out.println("House()");
    }
}
public class Test {
    public static void main(String[] args) {
        House h = new House();
    }
}

运行结果:
Window()
House()

从上例中可以看到,成员变量初始化先于构造方法运行。那么,对于静态成员来说,情况是否一样呢?来看看下面例子。

public class Bowl {
    Bowl(int marker){
        System.out.println("Bowl(" + marker + ")");
    }
    void f1(int marker){
        System.out.println("f1(" + marker + ")");
    }
}

public 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);
}

public 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 Test {
    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(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)

初始化顺序是先初始化静态对象(如果它们因前面的对象创建过程而被初始化),而后是非静态对象

如果大家知道这一点,上面输出结果就不难解释了——Test类中,先初始化table,进入table类中先有静态属性bowl1,再进入Bowl类中,发现没有成员变量,直接调用Bowl的构造方法,输出Bowl(1)。再回到Table类中,再有静态属性bowl2,同理输出Bowl(2)。然后调用Table类的构造方法,输出Table()f1(1),此时Test类中的静态属性table初始化完成,再根据相同的原则初始化cupboard。**不过这里值得注意的是,静态属性只会初始化一次。**最后执行main()方法里的内容。

最后,我们来总结一下对象的创建过程,假设有个名为Dog的类:

  1. 即使没有显式地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog地对象时,或者Dog类地静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
  2. 然后载入Dog.class,有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
  3. 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
  4. 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值,而引用则被设置成了null。
    5、执行所有出现于字段定义处的初始化动作。
    6、执行构造器。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值