类成员初始化

在类内部:初始化的顺序

  1. 静态的成员变量;
  2. 普通的成员变量;
  3. 构造器的调用。

在派生类中:初始化的顺序

  1. 调用基类的构造器
  2. 按声明顺序调用成员的初始化方法
  3. 调用派生类构造器主体

大多数类的初始化都是按照这些顺序结合在一起的。

下面是一个例子:

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;
    }
}
outputCup(1)
Cup(2)
field
Cups()
field
Cups()
Inside main()
f(99)
成功构建 (总时间: 1 秒)

根据上面所说的顺序,相信大家都会看得懂的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值