【12月7日】类的初始化(二):构造器初始化


可以用构造器来进行初始化,但是无法阻止自动初始化的进行,因为自动初始化会在构造器被调用之前发生。因此,假如使用一下代码:

Public class Counter{
int I;
Counter(){i=7;}
}

那么i首先会被置为默认值0,然后再变成7。对于所有基本类型(都有初始值)和对象的引用(初始值是null),包括在定义时已经指定初始值的变量,这种情况都是成立的。

1.   初始化顺序

在类的内部,变量定义的先后顺序决定了初始化的顺序。需要注意的是,即使变量定义和方法定义混杂在一起(如非必要,这真是个糟糕的编程习惯,好在我有世界第一好用ide--IDEA),它们仍让会在任何方法(包括构造器)被调用之前得到初始化。

2.静态数据的初始化

无论创建多少个对象,静态数据都指占用一份存储区域。同样,《think in JAVA》上有一个很经典的例子!大早上coding这个,表示已经晕的不行不行的。

 

package com.tree.jvm;

/**
 * Created by Administrator on 2016/12/7.
 */

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

class Table{
    static  Bowl bowl1 = new Bowl(1);

    public Table() {
        System.out.println("Table()");
        bowl2.f1(1);
    }

    void f2(int maker){
        System.out.println("f2("+maker+")");
    }

    static Bowl bowl2 = new Bowl(2);
}

class Cupboard{
    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);
    public Cupboard() {
        System.out.println("Cupboard()");
        bowl4.f1(2);
    }
    void  f3(int maker){
        System.out.println("f3("+maker+")");
    }
    static  Bowl bowl5 = new Bowl(5);

}


public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("createing new Cupboard() in main");
        new Cupboard();
        System.out.println("createing new Cupboard() in main again");
        new Cupboard();
        table.f2(1);
        cupboard.f3(1);
    }

    static Table table = new Table();
    static  Cupboard cupboard = new Cupboard();
}


 

Bowl类使得看到类的创建,而Table类和Cupboard类在它们的类定义中加入了Bowl类型的静态数据变量。Attention,Cupboard类先定义了一个Bowl类型的非静态数据成员(Bowl bowl3 = new Bowl(3))。

从输出结果中,可以得到以下信息:

一.程序首先对静态变量table进行初始化:

(1)首先初始化Table类中的静态变量bow1,bow2;

(2)这引发了Bowl类初始化,打印输出Bowl(1),Bowl(2);

(3)执行Table的构造器,打印输出Table(),和f1();

二.对静态变量cupboard进行初始化:

(1)首先初始化静态变量bowl4,bowl5;

(2)再初始化非静态变量bow3—注意此处不是按照定于顺序进行初始化,而是先静态后非静态;

(3)执行Cupboard的构造器,打印输出Cupboard()和f1(2);

三.执行main方法

 

由此可见,静态初始化只有在必要的时候才会进行。如果不创建Table对象,也不应用Table.bowl1和Table.bowl2,那么静态的Bowl bowl1和bowl2就永远不会被创建。只有在第一个Table对象被创建(或者第一次访问静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化。可以从上例看出, new了两次Cupboard

的静态数据是一样的。

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

从上例的输出结果中也可以看出这一点。要执行main()(静态方法),必须加载StaticInitialization类,乃后其静态域中的table和cupboard被初始化,这引发了它们对应的类也被加载,并且由于它们都包含静态的Bowl对象,因此Bowl随后也被加载。这样,在这个特殊的程序中所有的类在main()方法开始之前都被加载了。但是实际情况通常不是这样的。

总结一下类的创建过程,假设要创建一个类,姑且命名为Tree()吧:

1.      即使没有显示的使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Tree的对象时(构造器可以看成静态方法),或者首次访问Tree的静态方法/静态域时,JAVA解释器必须查找其路径,以定位Tree.class文件。

2.      然后载入Tree.class(创建一个class对象),有关静态初始化的所有动作都会被执行。因此,静态初始化只在首次加载的时候进行一次。

3.      当用new Tree()创建对象的时候,首先会在堆内存上为Tree对象分配足够的内存空间。

4.      这块空间会被清楚,将Tree对象中的所有基本类型数据都设置为默认值。

5.      执行所有出现在字段定义处的初始化动作。

6.      执行构造器。(可能会涉及到很多动作,尤其是涉及到继承问题时)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值