java initialize_java 初始化

初始化顺序

在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,

那些变量仍会在调用任何方法之前得到初始化——甚至在构建器调用之前。例如:

//: OrderOfInitialization.java

// Demonstrates initialization order.

// When the constructor is called, to create a

// Tag object, you'll see a message:

class Tag {

Tag(int marker) {

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

}

}

class Card {

Tag t1 = new Tag(1); // Before constructor

Card() {

// Indicate we're in the constructor:

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

t3 = new Tag(33); // Re-initialize t3

}

Tag t2 = new Tag(2); // After constructor

void f() {

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

}

Tag t3 = new Tag(3); // At end

}

public class OrderOfInitialization {

public static void main(String[] args) {

Card t = new Card();

t.f(); // Shows that construction is done

}

112

} ///:~

在Card 中,Tag 对象的定义故意到处散布,以证明它们全都会在构建器进入或者发生其他任何事情之前得到

初始化。除此之外,t3 在构建器内部得到了重新初始化。它的输入结果如下:

Tag(1)

Tag(2)

Tag(3)

Card()

Tag(33)

f()

因此,t3 句柄会被初始化两次,一次在构建器调用前,一次在调用期间(第一个对象会被丢弃,所以它后来

可被当作垃圾收掉)。

静态数据的初始化

若数据是静态的(static),那么同样的事情就会发生;如果它属于一个基本类型(主类型),而且未对其

初始化,就会自动获得自己的标准基本类型初始值;如果它是指向一个对象的句柄,那么除非新建一个对

象,并将句柄同它连接起来,否则就会得到一个空值(NULL)。

如果想在定义的同时进行初始化,采取的方法与非静态值表面看起来是相同的。但由于static 值只有一个存

储区域,所以无论创建多少个对象,都必然会遇到何时对那个存储区域进行初始化的问题。下面这个例子可

将这个问题说更清楚一些:

class Bowl {

Bowl(int marker) {

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

}

void f(int marker) {

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

}

}

class Table {

static Bowl b1 = new Bowl(1);

Table() {

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

b2.f(1);

}

void f2(int marker) {

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

}

static Bowl b2 = new Bowl(2);

}

class Cupboard {

Bowl b3 = new Bowl(3);

113

static Bowl b4 = new Bowl(4);

Cupboard() {

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

b4.f(2);

}

void f3(int marker) {

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

}

static Bowl b5 = new Bowl(5);

}

public class StaticInitialization {

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();

t2.f2(1);

t3.f3(1);

}

static Table t2 = new Table();

static Cupboard t3 = new Cupboard();

} ///:~

Bowl 允许我们检查一个类的创建过程,而Table 和Cupboard 能创建散布于类定义中的Bowl 的static 成

员。注意在static 定义之前,Cupboard 先创建了一个非static 的Bowl b3。它的输出结果如下:

Bowl(1)

Bowl(2)

Table()

f(1)

Bowl(4)

Bowl(5)

Bowl(3)

Cupboard()

f(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f(2)

f2(1)

f3(1)

static 初始化只有在必要的时候才会进行。如果不创建一个Table 对象,而且永远都不引用Table.b1 或

Table.b2,那么static Bowl b1 和b2 永远都不会创建。然而,只有在创建了第一个Table 对象之后(或者

发生了第一次static 访问),它们才会创建。在那以后,static 对象不会重新初始化。

在这里有必要总结一下对象的创建过程。请考虑一个名为Dog 的类:

(1) 类型为Dog 的一个对象首次创建时,或者Dog 类的static 方法/static 字段首次访问时,Java 解释器

必须找到Dog.class(在事先设好的类路径里搜索)。

(2) 找到Dog.class 后(它会创建一个Class 对象,这将在后面学到),它的所有static 初始化模块都会运

行。因此,static 初始化仅发生一次——在Class 对象首次载入的时候。

(3) 创建一个new Dog()时,Dog 对象的构建进程首先会在内存堆(Heap)里为一个Dog 对象分配足够多的存

储空间。

(4) 这种存储空间会清为零,将Dog 中的所有基本类型设为它们的默认值(零用于数字,以及boolean 和

char 的等价设定)。

(5) 进行字段定义时发生的所有初始化都会执行。

(6) 执行构建器。正如第6 章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时

显示的静态初始化

Java 允许我们将其他static 初始化工作划分到类内一个特殊的“static 构建从句”(有时也叫作“静态

块”)里。它看起来象下面这个样子:

class Spoon {

static int i;

static {

i = 47;

}

// . . .

尽管看起来象个方法,但它实际只是一个static 关键字,后面跟随一个方法主体。与其他static 初始化一

样,这段代码仅执行一次——首次生成那个类的一个对象时,或者首次访问属于那个类的一个static 成员时

(即便从未生成过那个类的对象)。例如:

//: ExplicitStatic.java

// Explicit static initialization

// with the "static" clause.

class Cup {

Cup(int marker) {

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

}

void f(int marker) {

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

}

}

class Cups {

static Cup c1;

static Cup c2;

static {

c1 = new Cup(1);

c2 = new Cup(2);

}

Cups() {

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

115

}

}

public class ExplicitStatic {

public static void main(String[] args) {

System.out.println("Inside main()");

Cups.c1.f(99); // (1)

}

static Cups x = new Cups(); // (2)

static Cups y = new Cups(); // (2)

} ///:~

输出结果如下:

aac387a6d3bf89a906e22eae284118e3.png

在标记为(1)的行内访问static 对象c1 的时候,或在行(1)标记为注释,同时(2)行不标记成注释的时候,用

于Cups 的static 初始化模块就会运行。若(1)和(2)都被标记成注释,则用于Cups 的static 初始化进程永

远不会发生。

非静态实例初始化

针对每个对象的非静态变量的初始化,Java 1.1 提供了一种类似的语法格式。下面是一个例子:

//: Mugs.java

// Java 1.1 "Instance Initialization"

class Mug {

Mug(int marker) {

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

}

void f(int marker) {

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

}

}

public class Mugs {

Mug c1;

Mug c2;

{

c1 = new Mug(1);

c2 = new Mug(2);

System.out.println("c1 & c2 initialized");

}

Mugs() {

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

}

public static void main(String[] args) {

System.out.println("Inside main()");

Mugs x = new Mugs();

}

} ///:~

输出结果如下

858d247f6425bbf638810087c4089d9d.png

大家可看到实例初始化从句:

{

c1 = new Mug(1);

116

c2 = new Mug(2);

System.out.println("c1 & c2 initialized");

}

它看起来与静态初始化从句极其相似,只是static 关键字从里面消失了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值