先看类中自身的初始化问题。
1、初始化变量的方法
一个类的成员变量的初始化有3种方式,在定义的时候直接初始化,在非静态代码块中初始化(静态代码块不呢个调用非静态成员变量),在构造器中初始化。
一个类变量(由static声明的变量)的初始化有4种方式,在定义的时候直接初始化,在非静态代码块中初始化和静态代码块中初始化,在构造器中初始化。
先看下面这段程序的执行结果:
public class Test1
{
private int a=8;//定义的时候直接指定初始值
private static int b=10;//定义的时候直接指定初始值
static
{
b=10;//在静态代码块中初始化
System.out.println("1");
}
{
a=20;//在非静态代码块中初始化
b=30;//在非静态代码块中初始化
System.out.println("2");
}
public Test1()
{
a=40;//在构造器中指定
b=50;//在构造器中指定
System.out.println("3");
}
public static void main(String[] args)
{
new Test1();
System.out.println("-----------");
new Test1();
}
}
输出结果:
1
2
3
----------
2
3
由上面的例子,就可以得出成员变量和类变量的初始化的方法,而且,在第一次加载Test1类的时候,会首先执行静态代码块,在执行非静态代码块,在执行构造器,如果不是第一次加载,在先执行非静态代码块,在执行构造器。
2、成员变量和类变量初始化先后顺序
上面我们已经知道了,类的第一次加载时,静态代码块先于代码块执行,代码块先于构造器。
那么
第一个问题:是成员变量先初始化还是类变量(静态成员变量)先初始化?
第二个问题:是直接指定的初始化先执行,还是在代码块的初始化先执行?
看下面的例子
在一个类中,如是定义两个成员变量当然是没问题的
int i=6;
int j=i+6;
如果像下面这样呢?当然是错的,因为成员变量的定义都是一个前向关系。
int j=i+6;
int i=6;
那么这样呢?将i声明为static
int j=i+6;
static int i=6;
实验结果是能通过编译的
这就说明了第一个问题:类变量(静态成员变量)先与成员变量初始化。
在来看第二个问题
第一段程序:
public class Test7
{
int i=8;
{
i=7;
}
public static void main(String[] args)
{
System.out.println(new Test7().i);
}
}
输出结果是 7
第二段程序:
public class Test7
{
{
i=7;
}
int i=8;
public static void main(String[] args)
{
System.out.println(new Test7().i);
}
}
输出结果是 8
从这里就可以明白第二个问题:直接指定的初始化和在代码块的初始化的执行先后与它们在程序中出现的先后顺序是一样的。
3、与父类相关的初始化问题
上面的情况都没有说明父类初始化的问题,实际上java中的所有类,都是直接或间接的继承Object基类,所以都会存在父类初始化的问题。
那么,这样的初始化会遵循什么规律:
(1)如何父类和子类都是第一次加载,那么先执行父类的静态代码块,在执行子类的静态代码块。
(2)在执行父类非静态代码块,在执行父类中被子类用super显示调用或者隐式调用的构造器。
(2)在执行子类的非静态代码块,在执行子类的构造器。