在类内部:初始化的顺序
- 静态的成员变量;
- 普通的成员变量;
- 构造器的调用。
在派生类中:初始化的顺序
- 调用基类的构造器
- 按声明顺序调用成员的初始化方法
- 调用派生类构造器主体
大多数类的初始化都是按照这些顺序结合在一起的。
下面是一个例子:
public class Test extends Sub{
public static int field = getField2();
public Test(){
System.out.println("test()");
}
public static void main(String[] args) {
new Test();
}
public static int getField2(){
System.out.println("test static");
return 1;
}
}
class Super{
public Super(){
System.out.println("super()");
}
public int field = 0;
public static int field2 = getField2();
public void fun1(){
System.out.println("super fun1");
}
public int getField(){
return field;
}
public static void fun2(){
System.out.println("super static fun2");
}
public static int getField2(){
fun2();
return 1;
}
}
class Sub extends Super{
public Sub(){
System.out.println("sub()");
}
public int field = getField();
public static int field2 = getField2();
public void fun1(){
System.out.println("sub fun1");
}
public int getField(){
fun1();
return 1;
}
public static void fun2(){
System.out.println("sub static fun2");
}
public static int getField2(){
fun2();
return 1;
}
}
下面我们看看输出的结果:
output:
super static fun2
sub static fun2
test static
super()
sub fun1
sub()
test()
成功构建 (总时间: 0 秒)
我们在main()方法中调用了new一个test的对象,由于test继承了sub,而sub继承了super。(当进行继承时,我们已经知道基类的一切,并且可以访问基类中任何声明为public和protected的成员。这意味着在派生类中,必须假定基类的所有成员都是有效的。一种标准方法是,构造动作一经发生,那么对象所有部分的全体成员都会得到构建。然而,在构造器内部,我们必须确保所要使用的成员都已经构建完毕。为确保这一目的,唯一的办法就是首先调用基类的构造器。那么在进入派生类构造器时,在基类中可供我们访问的成员都已得到初始化。)
只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。
所以static变量是最先初始化的,并根据基类到派生类的顺序。
当static变量初始化之后,下一个执行的就是基类super的实例变量,然后在轮到super的构造器。
接着就是sub的实例变量和构造器。我们可以看到sub的构造器执行之前有sub fun1的输出。这就证明是先初始化实例变量再执行构造器的。
当基类都初始化完成时,在轮到派生类。
实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。而静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
也就是说实例变量在每个对象的创建都会初始化,而静态变量只会在第一次加载类时初始化(只会初始化一次)。
下面是一个例子:
public class ExplicitStatic {
public static void main(String[] args) {
System.out.println("Inside main()");
Cups.cup1.f(99);
}
static Cups cup1 = new Cups();
static Cups cup2 = new Cups();
}
class Cup {
Cup(int marker) {
System.out.println("Cup("+marker+")");
}
void f(int marker){
System.out.println("f(" + marker + ")");
}
}
class Cups {
static Cup cup1;
static Cup cup2;
public int field = getField();
static {
cup1 = new Cup(1);
cup2 = new Cup(2);
}
Cups() {
System.out.println("Cups()");
}
public int getField(){
System.out.println("field");
return 1;
}
}
output:
Cup(1)
Cup(2)
field
Cups()
field
Cups()
Inside main()
f(99)
成功构建 (总时间: 1 秒)
根据上面所说的顺序,相信大家都会看得懂的。