成员初始化
Java尽力保证:所有变量在使用前都能得到恰当的初始化。
对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。所以写成:
void f(){
int i;
i++;//Error - -i not initialized
}
就会得到一条出错消息,告诉你i可能尚未初始化。
当然,编译器也可以为i赋一个默认值,但是未初始化的局部变量更有可能使程序员的疏忽。
所以采用默认值反而会掩盖这种失误。
因此强制程序员提供一个初始值,往往能够帮助找出程序里的缺陷。
要是类的数据成员(即字段)是基本类型,情况就会变得有些不同。
正如在”一切都是对象“一章中所看到的,类的每个基本类型数据成员保证都会有一个初始值。
下面的程序可以验证这类情况,并显示它们的值:
//: initialization/InitialValues.java
// Shows default initial values.
import static net.mindview.util.Print.*;
public class InitialValues {
boolean t;
char c;
byte b;
short s;
int i;
long l;
float f;
double d;
InitialValues reference;
void printInitialValues() {
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);
}
public static void main(String[] args) {
InitialValues iv = new InitialValues();
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
*///:~
可见尽管数据成员的初值没有给出,但它们确实有初值(char值为0,所以显示为空白)。
这样至少不会冒”为初始化变量“的风险。
在类里定义一个对象引用时,如果不将其初始化,此引用就会获得一个特殊值null。
Specifying initialization
指定初始化
如果想为某个变量赋初值,该怎么做呢?
有一种很直接的办法,就是在定义类成员变量的地方为其赋值(注意在C++中不能这样做,尽管C++的新手们总想这么做)。
以下代码片段修改了InitialValues类成员变量的定义,直接提供了初值:
//: initialization/InitialValues2.java
// Providing explicit initial values.
public class InitialValues2 {
boolean bool = true;
char ch = 'x';
byte b = 47;
short s = 0xff;
int i = 999;
long lng = 1;
float f = 3.14f;
double d = 3.14159;
} ///:~
也可以用同样的方法初始化非基本类型的对象。
如果Depth是一个类,那么可以像下面这样创建一个对象并初始化它”
//: initialization/Measurement.java
class Depth {}
public class Measurement {
Depth d = new Depth();
// ...
} ///:~
如果没有为d指定初始值就尝试使用它,就会出现运行时错误,告诉你产生了一个异常。。
甚至可以通过调用某个方法来提供初值:
//: initialization/MethodInit.java
public class MethodInit {
int i = f();
int f() { return 11; }
} ///:~
这个方法也可以带有参数,但这些参数必须是已经被初始化了的。因此,可以这样写:
//: initialization/MethodInit2.java
public class MethodInit2 {
int i = f();
int j = g(i);
int f() { return 11; }
int g(int n) { return n * 10; }
} ///:~
但像下面这样写就不对了“
//: initialization/MethodInit3.java
public class MethodInit3 {
//! int j = g(i); // Illegal forward reference
int i = f();
int f() { return 11; }
int g(int n) { return n * 10; }
} ///:~
显然,上述程序的正确性取决于初始化的顺序,而与其编译方式无关。
所以,编译器恰当地对”向前引用“发出警告
这种初始化方法既简单又直观。
但有个限制:类initialValues的每个对象都会具有相同的初值。
有时,这正是所希望的,但有时却需要更大的灵活性。