Java类初始化、实例化流程你真的清楚吗

一、前言

最近在SpringAOP的源码,里面涉及到一些类初始化、实例化的顺序,比如AbstractAutoProxyCreator的触发在初始化 bean 之后,实例化 bean之前。特写此文记录一下。

二、流程

1、类初始化流程

  1. 想创建一个类的实例,就需要先加载并初始化该类;
  2. 想要初始化一个子类,就需要先初始化父类(extends);
  3. 所谓类的初始化就是执行<clinit>()方法:
    • <clinit>()方法由静态类变量显式的赋值代码 和 静态代码块组成(static关键字);
    • 并且<clinit>()方法只会执行一次。

2、类实例化流程

实例化一个类时,就是执行<init>()方法:

  1. <init>()方法可能会重载多个,因为有几个构造器就有几个<init>()方法;
  2. <init>()方法由非静态实例变量显示赋值代码、非静态代码块、对应构造器代码组成;
  3. 非静态实例变量显示赋值代码、非静态代码块代码从上到下顺序执行(谁先出现谁先加载),构造器的代码最后执行。
  4. 每次创建实例对象时,都会调用相应的构造器,即执行对应的<init>()方法;
  5. <init>()方法的首行是super()或super(Object …),即对应父类的<init>()方法,也就是说类实例化也是先实例化父类。

3、方法重写过程

1> 方法重写正是对象多态性的体现:

  1. 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码;
  2. 非静态方法默认的调用对象是this,即:非静态方法前面有一个默认的对象this;
  3. this对象在构造器(<init>()方法)中其实就是正在创建的对象;

2> 不可被重写的方法?

  • final方法
  • 静态方法
  • private等子类不可见的方法

三、验证

1、代码案例

创建一个父类Father、一个子类Son(extends Father);

1)Father

package com.saint.base.base;

/**
 * @author Saint
 */
public class Father {
    
    

    // 构造器
    Father() {
    
    
        System.out.println("father constructor(1)");
    }

    // 静态代码块
    static {
    
    
        System.out.println("father static code block(2)");
    }

    // 普通代码块
    {
    
    
        System.out.println("father common code block(3)");
    }

    // 静态成员变量
    private static int i = staticMember();

    // 成员变量
    private int j = member();

    /**
     * 静态方法
     */
    public static int staticMember() {
    
    
        System.out.println("father static method for static member(4)");
        return 1;
    }

    /**
     * 成员方法
     */
    public int member() {
    
    
        System.out.println("father method for common member(5)");
        return 1;
    }
}

2)Son

package com.saint.base.base;

/**
 * @author Saint
 */
public class Son extends Father{
    
    

    // 构造器
    Son() {
    
    
        // super()写或不写,在子类构造器中一定会先调用父类的构造器
//        super();
        System.out.println("son constructor(6)");
    }

    // 静态代码块
    static {
    
    
        System.out.println("son static code block(7)");
    }

    // 普通代码块
    {
    
    
        System.out.println("son common code block(8)");
    }

    // 静态成员变量
    private static int i = staticMember();

    // 成员变量
    private int j = member();

    /**
     * 静态方法
     */
    public static int staticMember() {
    
    
        System.out. println("son static method for static member(9)");
        return 1;
    }

    /**
     * 成员方法
     */
    public int member() {
    
    
        System.out.println("son method for common member(10)");
        return 1;
    }

    public static void main(String[] args) {
    
    
        System.out.println("---------第1次实例化Son对象----------");
        Son son1 = new Son();
        System.out.println();
        System.out.println("---------第二次实例化Son对象----------");
        Son son2 = new Son();
    }
}

2、Son类main()运行结果

在这里插入图片描述

1)结果分析

  1. 实例化子类时要先实例化父类;
  2. 先加载父类静态变量和静态代码块,再加载子类静态变量和静态代码块;
  3. 若子类重写父类方法,则父类调用的是子类方法代码;
  4. 然后再先加载父类非静态变量和非静态代码块、构造方法,再加载子类非静态变量和非静态代码块、构造方法;
  5. 仅初始化是静态变量和静态方法会被执行一次;非静态变量、非静态方法、构造器则是对象实例化一次执行一次。

猜你喜欢

转载自blog.csdn.net/Saintmm/article/details/125596829