Java 类的实例变量初始化、静态块、非静态块、构造函数的加载顺序

Java 类的实例变量初始化、静态块、非静态块、构造函数的加载顺序

例1:
public class Baset {

    private String baseName = "base";
    
    // 构造方法
    public Baset() {
        callName();
    }

    // 成员方法
    public void callName() {
        System.out.println("父类=====>basename:" + baseName);
    }

    //静态内部类
    static class Sub extends Baset {//static必须写在开头
        // 静态字段
        private String baseName = "sub";

        public Sub() {
            callName();
        }

        // 重写父类的方法
        public void callName() {
            System.out.println("子类=====>subname:" + baseName);
        }
    }

    public static void main (String[] args){
        Baset base = new Sub();
    }	
}

求这段程序的输出。
解答此题关键在于理解和掌握类的加载过程以及子类继承父类后,重写方法的调用问题:

从程序的执行顺序去解答:

1.编译;当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class 文件加载到内存

2、Base base= new Sub():
声明父类变量base对子类的引用,JAVA类加载器将Base,Sub类加载到JVM(Java虚拟机);

3、JVM为Base,Sub 的的成员开辟内存空间
此时,Base 和Sub类中的值为null;

4、new Sub();
这个时候会调用Sub类的隐式构造方法,
Sub的构造方法本质为:

 public Sub(){

  super();//  调用父类的构造方法。必须在构造方法中的第一行,为什么呢?这是因为在一些程序的升级中,要兼容旧版本的一些功能,父类即原先的一些初始化信息也要保证  //被执行到,然后执行当前

  baseName = "sub";//子类字段初始化

  }

new Sub()执行到super()这行代码也就是跑到父类中去执行了,我们跳转到父类中的无参构造方法中执行,最后执行Sub()中的baseName = “sub”

5、public Base() ;

父类无参构造方法的本质为:

public Base(){

  baseName= "base";//父类字段初始化

  callName();

  }

即将父类的baseName赋值为“base”,赋值后调用callName();

6、callName()方法在子类中被重写,因此调用子类的callName(),子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行。

7、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才为子类字段baseName 分配好存储空间,随后为其赋值:

可见,在baseName = "sub"执行前,子类的callName()已经执行,所以子类的baseName为默认值状态null;

其结果:
子类=====>subname:null
子类=====>subname:sub
例2:
public class BaseTest {

    // 父类变量
    private String baseName = "base";
    // 父类静态变量
    private static String staticField = "父类静态变量";

    // 父类静态方法
    public static void Order() {
        System.out.println("父类静态方法-");
        System.out.println("父类=====>staticField:" + staticField);
    }

    // 父类静态初始代码块
    static {
        System.out.println("父类静态初始化代码块-");
        System.out.println("父类=====>staticField:" + staticField);
    }

    // 初始化代码块
    {
        System.out.println("父类非静态初始化代码块-");
        System.out.println("父类=====>baseName:" + baseName);
    }

    // 构造函数
    public BaseTest() {
        System.out.println("父类构造方法");
        callName();
    }

    // 成员方法
    public void callName() {
        System.out.println("父类callName方法-");
        System.out.println("父类=====>baseName:" + baseName);
    }

    // 静态内部类
    static class Sub extends BaseTest {
        // 子类变量
        private String baseName = "sub";
        // 子类 静态变量
        private static String staticField = "子类静态变量";

        // 子类静态方法
        public static void Order() {
            System.out.println("子类静态方法-");
            System.out.println("子类=====>staticField:" + staticField);
        }

        // 子类静态初始化代码块
        static {
            System.out.println("子类静态初始化代码块-");
            System.out.println("子类=====>staticField:" + staticField);
        }

        // 子类非静态初始化代码块
        {
            System.out.println("子类非静态初始化代码块-");
            System.out.println("子类=====>baseName:" + baseName);
        }

        public Sub() {
            System.out.println("子类构造方法");
            callName();
        }

        public void callName() {
            System.out.println("子类重写父类callName方法-");
            System.out.println("子类=====>baseName:" + baseName);
        }
    }

    public static void main(String[] args) {

        BaseTest b = new Sub();

        System.out.println("*********************************************");
        Sub.Order();
        System.out.println("=====>"+Sub.staticField);
        System.out.println("----->"+BaseTest.staticField);
        BaseTest.Order();
        System.out.println("*********************************************");

    }
}
程序总结:
1)、java中的块分为静态块(static{})和非静态块({}),这两种的执行是有区别的:
    
    非静态块的执行时间是:在执行构造函数之前。   静态块的执行时间是:class文件加载时执行。
    
    static类型的属性也是在类加载时执行的。


2)、可见Java类的实例变量初始化的过程:
    
    static类型的成员属性执行,静态块(static{})按顺序执行,然后非静态成员变量初始化,非静态代码块({})执行,最后执行构造方法。

   	static类型与static块按先后顺序执行。
其结果:
父类静态初始化代码块-
父类=====>staticField:父类静态变量
子类静态初始化代码块-
子类=====>staticField:子类静态变量
父类非静态初始化代码块-
父类=====>baseName:base
父类构造方法
子类重写父类callName方法-
子类=====>baseName:null
子类非静态初始化代码块-
子类=====>baseName:sub
子类构造方法
子类重写父类callName方法-
子类=====>baseName:sub
*********************************************
子类静态方法-
子类=====>staticField:子类静态变量
=====>子类静态变量
----->父类静态变量
父类静态方法-
父类=====>staticField:父类静态变量
*********************************************
注意:
1)、因静态变量、静态代码块,是在类加载的时候执行的,所以顺序是最先执行。如果有父类,则先执行父类中静态,再执行子类中的静态;
2)、静态块执行后,再执行非静态块,首先执行父类中静态块,在执行父类中的构造函数。然后在执行子类中静态块。
3)、如果子类中重写父类中的方法。则实例化子类时,父类会执行子类重写后的方法。则只实例化父类,父类会执行自己本身的方法,与子类重写后的方法无关。
4)、执行顺序依次为:
		父类静态
		子类静态
		父类非静态
		父类构造
		子类非静态
		子类构造
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值