java变量的初始化顺序

假设子类B继承了父类A,当执行语句new B()或者new B(…)语句之后
1. 类的装载 (多次实例化只装载一次)

(1). 首先要进行类A和B的装载(类只有在使用New调用创建的时候才会被 java类装载器装入),先装载父类A,再装载子类B

2. 静态初始化 (多次实例化只初始化一次)

(1). 装载父类A后,完成静态动作(包括静态代码块和变量,它们的级别是相同的,按代码中出现的顺序初始化), 这里需要注意的是装载静态代码的时候,首先为静态变量分配内存空间,赋上默认值,但不把 = 后面的值赋给它(如果存在=后面的值),然后再按出现的顺序依次执行(包括static变量赋值和static代码块).

// 比如这种情况也是ok的
static{
    i = 10;
}   
public static int i = 20;

(2). 装载子类B后,同样完成静态动作,同父类A装载.

3. 实例化 (每次实例化都初始化)

(1). 在实例化子类B之前,先要实例化父类A(包括非静态代码块和变量,它们的级别是相同的,按代码中出现的顺序初始化),这里同样需要注意的是在执行代码之前,首先为成员变量分配内存空间,赋上默认值,但不把 = 后面的值赋给它(如果存在=后面的值),然后再按出现的顺序依次执行(包括实例变量赋值和实例代码块),与static初始化类似.

`

(2). 执行父类A的构造方法,这里如果子类B不指定,则执行父类A的默认构造方法,若父类没有默认的构造方法,则需要子类指定需要执行父类A的某个构造方法,否则编译不通过.

public B() {

}
/** 如果父类有默认构造super()就等同于如下代码 */
public B() {
    super();
    /** 如果父类没有默认构造super(), 则这里需要指定, 如super(...) */
}

(3). 子类B的成员实例化,与父类A实例化类似.

(4). 最后执行子类B的构造方法.

补充:
后来遇到一种情况, 存在子类方法覆盖方法的情况.

public class B extends A {
    public int i = 10;

    public B() {
        System.out.println("B draw");
    }
    public void draw() {
        System.out.println("B draw " + i);
    }
    public static void main(String[] args) {
        B b = new B();
        b.draw();
    }
}
class A {
    public void draw() {
        System.out.println("A draw");
    }
    public A() {
        System.out.println("begin");
        draw();
        System.out.println("end");
    }
}

/* 输出是
    begin
    B draw 0
    end
    B draw
    B draw 10
*/

这里父类的构造方法调用了draw()方法, 但实际调用的是子类中的方法, 方法中访问了变量 i, 结果为0. 所以java在实例化的时候, 都已经将类(父类和子类)中的变量和方法都已经分配好了内存空间,并且变量赋值为默认值, 然后再按照上述的规则进行初始化.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值