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
如果我们在定义类成员变量时没有为其定义初值,那么编译器就会自动为其加上初值。boolean
为false
,short
、int
、long
为0
,float
、double
为0.0
,char
为0
所以显示为空。
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
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的类:
- 即使没有显式地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog地对象时,或者Dog类地静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
- 然后载入Dog.class,有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
- 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
- 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值,而引用则被设置成了null。
5、执行所有出现于字段定义处的初始化动作。
6、执行构造器。