“5.6 成员初始化”,之前提到过,雷的数据成员如果是基本类型,都会保证有一个初始值。下面的程序可以验证这一类的情况:
importstaticnet.mindview.util.Print.*; publicclassInitialValues { booleant; charc; byteb; shorts; inti; longl; floatf; doubled; InitialValuesreference; voidprintInitialValues() { print("Data type Initial value"); print("boolean "+t); print("char ["+c+"]"); print("byte "+b); print("short "+s); print("int "+i); print("long "+l); print("float "+f); print("double "+d); print("reference "+reference); } publicstaticvoidmain(String[] args) { InitialValuesiv=newInitialValues(); iv.printInitialValues(); /* You could also say: new InitialValues().printInitialValues(); */ } }
/* Output:
Data type Initial value
boolean false
char [ ]
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
reference null
*///:~
这样做至少能保证不会报“未初始化变量”的错误,而且可以发现,在类里定义一个对象引用时,如果不将其初始化,此应用就会获得一个特殊值null。虽然是null,也是得到初始化的,只是使用的时候会报NullPointException的异常错误,这个错误是以后Java程序员经常会遇到的。
“5.6.1 指定初始化”,如果想为莫个变量赋初始值,其实方法很多,最简单的一种就是定义的时候直接提供初始值:
publicclassInitialValues2 { booleanbool=true; charch=‘x’; byteb=47; shorts=0xff; inti=999; longlng=1; floatf=3.14f; doubled=3.14159; }
///:~
也可以用同样的方法初始化非基本类型的对象。如果Depth是一个类,那么可以像下面这样创建一个对象并初始化它:
classDepth {} publicclassMeasurement { Depthd=newDepth(); // ... }
///:~
虽然上面的方式达到了初始化成员变量的效果,但是这种方式并没有给程序带来更大的灵活性。下面介绍一种常用的初始化方法,就是”5.7 构造器初始化”这一小节要介绍的东西。
在这里首先要说明一点,就是你无法阻止自动初始化的进行,它将在构造器被调用之前发生。因此,假如使用下述代码:
publicclassCounter { inti; Counter() { i=7; } // ... }
///:~
那么i首先会被置为0,然后变成7.对于所有基本类型和对象引用,包括在定义时已经指定初始值的变量,这种情况都是成立的。这一点在很多考试中经常遇到,考题就是先输出什么值,再输出什么值,如果不理解这一点,肯定会选不出正确答案。这在下面的”5.7.1 初始化顺序”这一小节会让你觉得更加凌乱。虽然我们在未来做开发的时候,不会让自己的设计变得这么复杂,但是在这里跟着这本经典著作一点一点学习一门编程语言的执行机制,会让你变得更加优秀。
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散步于方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。例如:
importstaticnet.mindview.util.Print.*; // When the constructor is called to create a // Window object, you’ll see a message: classWindow { Window(intmarker) { print("Window("+marker+")"); } } classHouse { Windoww1=newWindow(1); // Before constructor House() { // Show that we’re in the constructor: print("House()"); w3=newWindow(33); // Reinitialize w3 } Windoww2=newWindow(2); // After constructor voidf() { print("f()"); } Windoww3=newWindow(3); // At end } publicclassOrderOfInitialization { publicstaticvoidmain(String[] args) { Househ=newHouse(); h.f(); // Shows that construction is done } }
/* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~
在House中,故意把几个Window对象的定义散步到各处,以证明他们全都会在调用构造器或其他方法之前得到初始化。此外,w3在构造器中再次被初始化。可以自己加一些类或者基本类型的数据成员,运行一下体会这些顺序。