1. 实例变量的初始化
对于实例变量而言,它属于Java对象,每次程序创建新的Java对象都会为其实例变量分配空间,并执行初始化。程序可以在三个地方对其进行初始化:
(1)定义示例变量时指定初始值;
(2)非静态初始化块中对实例变量指定初始值;
(3)构造器中对实例变量指定初始值。
其中(1)(2)两种方式比(3)先执行,但是顺序由其在源代码中的顺序决定。
下面的示例可以演示三种初始化的运行顺序。
public class Dog {
public Dog(int age, String name) {
System.out.println("Constructor: " + this);
this.age = age; //(3)构造器中对实例变量指定初始值
this.name = name;
}
{
System.out.println("Block one: " + this);
age = 20; //(2)非静态初始化块中对实例变量指定初始值
name = "Huahua";
System.out.println("Block two: "+this);
}
int age = 10; //(1)定义示例变量时指定初始值
String name;
public String toString() {
return "Dog: " + name + ", age: " + age;
}
public static void main(String[] args) {
Dog d = new Dog(5, "Wangwang");
System.out.println(d);
}
}
结果如下:
Block one: Dog: null, age: 0
Block two: Dog: Huahua, age: 20
Constructor: Dog: Huahua, age: 10
Dog: Wangwang, age: 5
可以看出实际的执行顺序。
再结合javap的结果,我们可以看出,实例变量实际的初始化过程是这样的:先进行变量声明,然后将变量赋值全部提取到构造器中运行。拿age的初始化来举例,先执行int age;语句,然后将age的赋值全部提取到构造器中,顺序和源代码中一样,然后执行。也就是变成了下面这样:
public class Dog {
int age;
String name;
public Dog(int age, String name) {
System.out.println("Block one: " + this);
this.age = 20;
this.name = "Huahua";
System.out.println("Block two: "+this);
this.age = 10;
System.out.println("Constructor: " + this);
this.age = age;
this.name = name;
}
public String toString() {
return "Dog: " + name + ", age: " + age;
}
public static void main(String[] args) {
Dog d = new Dog(5, "Wangwang");
System.out.println(d);
}
}
2.类变量的初始化
类变量的初始化有两种方式:
(1)定义类变量时指定初始值;
(2)静态初始化块中队类变量指定初始值
这两种方式的执行顺序与他们在源程序中的排列顺序相同。而且类变量的初始化过程与实例变量的初始化过程有一点类似,也是先声明变量,然后再进行赋值。
例如
public class Price {
{
System.out.println(initPrice);
initPrice = 30;
}
static{
//System.out.println(initPrice); Error:Cannot reference a field before it is defined
initPrice = 40;
}
final static Price INSTANCE = new Price(2.8);
static double initPrice= 20;
double currentValue;
public Price(double discount) {
System.out.println(initPrice);
currentValue = initPrice - discount;
}
public static void main(String[] args) {
Price price = new Price(2.8);
System.out.println(INSTANCE.currentValue);
System.out.println(price.currentValue);
}
}
经过编译器处理后的实际执行顺序变为:
(1)加载Price类,声明类变量INSTANCE、initPrice;
(2)将initPrice赋值为40;
(3)初始化INSTANCE,运行构造函数(其中非静态初始化中的两条语句被提取到构造函数中),打印initPrice的值,为40,将initPrice赋值为30,然后再次打印initPirce的值为30,最后INSTANCE的currentValue被赋值为27.2,INSTANCE初始化完毕。
(4)继续运行initPrice的赋值语句将其赋值为20。
(5)对main函数中声明的Price对象进行初始化,首先打印initPirce的值为20,然后赋值为30,最后对currentValue赋值为27.2 。
整个初始化结束。