概述:
先静态对象(只初始化一次),再是”非静态“对象。
[静态对象之间/非静态对象之间的初始化顺序取决于它们之间定义的先后顺序]
原理:
假设创建名为Dog类的对象:
- 当首次创建Dog类的对象时,或者Dog类的静态方法/静态域首次被访问(即便从未生成Dog类的对象)时,java解释器必须查找类路径,以定位Dog.class文件
- 然后载入Dog.class(后面会讲到,这将创建了一个Class对象),有关的静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的的时候进行一次.
- 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
- 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值。
- 执行所有出现于字段定义处的初始化动作。
- 执行构造函数。
实战验证:
实验一:
class Father
{
{
System.out.println("Father的实例初始化子句");
a++;//这语句正确是因为它是static,先初始化
}
static
{
System.out.println("Father的静态初始化子句");
}
Father()
{
System.out.println("Father的构造函数中a=" + a+ ",b=" + b);//构造函数可以引用a,b是因为构造函数是最后一部执行的
}
static int a=2;
int b=2;
}
public class Main {
public static void main(String[] args) {
System.out.println("第一次创建Father");
new Father();
System.out.println("第二次创建Father");
new Father();
}
}
/*Output
*第一次创建Father
*Father的静态初始化子句
*Father的实例初始化子句
*Father的构造函数中a=3,b=2
*第二次创建Father
*Father的实例初始化子句
*Father的构造函数中a=4,b=2
*/
分析结果:
- 静态成员(包括语句块)只初始化一次
- 静态的初始化先于非静态的
- 构造函数在所有字段定义并初始化后再执行的
- 从错误1,2可见,同等级之间初始化顺序取决于定义的顺序(同等级即同为非静态成员之间或同为静态成员之间)
实验二:加了继承,结果会怎么样?
class Father
{
{
System.out.println("Father的实例初始化子句");
}
static
{
System.out.println("Father的静态初始化子句");
}
Father()
{
System.out.println("Father的构造函数中");
}
}
class Child extends Father
{
{
System.out.println("Child的实例初始化子句");
}
static
{
System.out.println("Child的静态初始化子句");
}
Child()
{
System.out.println("Child的构造函数");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("第一次创建Child");
new Child();
System.out.println("第二次创建Child");
new Child();
}
}
/*Output
*第一次创建Child
*Father的静态初始化子句
*Child的静态初始化子句
*Father的实例初始化子句
*Father的构造函数中
*Child的实例初始化子句
*Child的构造函数
*第二次创建Child
*Father的实例初始化子句
*Father的构造函数中
*Child的实例初始化子句
*Child的构造函数
*/
分析结果:
对比实验一,多了一条结论存在继承的情况下:父类静态 > 子类静态 > 父类非静态 > 子类非静态 > 父类构造函数 > 子类构造函数
实验三:不生成子类的对象。
class Father
{
{
System.out.println("Father的实例初始化子句");
}
static
{
System.out.println("Father的静态初始化子句");
}
Father()
{
System.out.println("Father的构造函数中" );
}
}
class Child extends Father
{
{
System.out.println("Child的实例初始化子句");
}
static
{
System.out.println("Child的静态初始化子句");
}
Child()
{
System.out.println("Child的构造函数");
}
static void print()
{
System.out.println("Child的print函数");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("第一次");
Child.print();
System.out.println("第二次");
Child.print();
}
}
/*Output
第一次
*Father的静态初始化子句
*Child的静态初始化子句
*Child的print函数
*第二次
*Child的print函数
*/
分析结果:
- 静态对象的初始化不仅可以通过首次创建该类的对象,还可以通过首次调用该类的静态成员方法
总结:
- 任何时候,初始化顺序:静态 > 非静态,
- 同等级之间的初始化顺序取决于定义的顺序
- 存在继承的情况下:父类静态 > 子类静态 > 父类非静态 > 子类非静态
- 构造函数在所有字初始化之后执行。
- 静态变量初始化只发生在首次创建该类的对象或者首次调用该类的静态成员方法