一、前言
最近在SpringAOP的源码,里面涉及到一些类初始化、实例化的顺序,比如AbstractAutoProxyCreator的触发在初始化 bean 之后,实例化 bean之前。特写此文记录一下。
二、流程
1、类初始化流程
- 想创建一个类的实例,就需要先加载并初始化该类;
- 想要初始化一个子类,就需要先初始化父类(extends);
- 所谓类的初始化就是执行
<clinit>()
方法:
<clinit>()
方法由静态类变量显式的赋值代码 和 静态代码块组成(static关键字);- 并且
<clinit>()
方法只会执行一次。
2、类实例化流程
实例化一个类时,就是执行
<init>()
方法:
<init>()
方法可能会重载多个,因为有几个构造器就有几个<init>()
方法;<init>()
方法由非静态实例变量显示赋值代码、非静态代码块、对应构造器代码组成;- 非静态实例变量显示赋值代码、非静态代码块代码从上到下顺序执行(谁先出现谁先加载),构造器的代码最后执行。
- 每次创建实例对象时,都会调用相应的构造器,即执行对应的
<init>()
方法;<init>()
方法的首行是super()或super(Object …),即对应父类的<init>()
方法,也就是说类实例化也是先实例化父类。
3、方法重写过程
1> 方法重写正是对象多态性的体现:
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码;
- 非静态方法默认的调用对象是this,即:非静态方法前面有一个默认的对象this;
- 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)结果分析
- 实例化子类时要先实例化父类;
- 先加载父类静态变量和静态代码块,再加载子类静态变量和静态代码块;
- 若子类重写父类方法,则父类调用的是子类方法代码;
- 然后再先加载父类非静态变量和非静态代码块、构造方法,再加载子类非静态变量和非静态代码块、构造方法;
- 仅初始化是静态变量和静态方法会被执行一次;非静态变量、非静态方法、构造器则是对象实例化一次执行一次。