本文主要演示Java类的初始化顺序,分为有继承和没有继承两种情况。如有错误,劳烦指正,不胜感谢!
没有继承情况
直接上代码,工具类:
/**
* 工具类Log
*/
public class Log {
public static String baseFieldInit() {
System.out.println("父类普通成员变量");
return "";
}
public static String baseStaticFieldInit() {
System.out.println("父类静态成员变量");
return "";
}
public static String fieldInit() {
System.out.println("子类普通成员变量");
return "";
}
public static String staticFieldInit() {
System.out.println("子类静态成员变量");
return "";
}
}
父类:
/**
* 父类/基类 为了方便后面有继承的情况,所以这里直接使用父类
*/
public class Base {
static {
System.out.println("父类静态代码块 1");
}
private static String staticValue = Log.baseStaticFieldInit();
static {
System.out.println("父类静态代码块 2");
}
{
System.out.println("父类构造代码块 1");
}
private String value = Log.baseFieldInit();
{
System.out.println("父类构造代码块 2");
}
Base() {
System.out.println("父类构造方法");
}
public static void main(String[] args) {
//在 new 对象之前打印输出只是为了证明main方法虽然是程序入口,但是并不会最先执行
System.out.println("new 之前");
new Base();
System.out.println("new 之后");
}
}
输出:
父类静态代码块 1
父类静态成员变量
父类静态代码块 2
new 之前
父类构造代码块 1
父类普通成员变量
父类构造代码块 2
父类构造方法
new 之后
结论:
- 静态代码块和静态成员变量并列优先级,按代码中出现的先后顺序执行,只有在第一次加载类时执行。
- 在执行完静态代码块之后,会执行main方法中,实例化对象(
new
)之前的代码。 - 构造代码块和普通成员变量并列优先级,按代码中出现的先后顺序执行。
- 构造方法。
- 最后就是实例化对象(
new
)之后的代码。
注意:第1步只有在类第一次被加载的时候才运行。如果创建两个对象
new Base();
new Base();
第二次创建对象,就只执行第3步。
有继承的情况
这里创建一个子类Subclass
继承上述中的父类Base
,同时也使用了工具类Log
代码如下:
/**
* 子类/派生类
*/
public class SubClass extends Base {
static {
System.out.println("子类静态代码块 1");
}
private static String staticValue = Log.staticFieldInit();
static {
System.out.println("子类静态代码块 2");
}
{
System.out.println("子类普通代码块 1");
}
private String value = Log.fieldInit();
{
System.out.println("子类普通代码块 2");
}
SubClass() {
System.out.println("子类构造方法");
}
public static void main(String[] args) {
System.out.println("new 之前");
SubClass sub = new SubClass();
System.out.println("new 之后");
}
}
输出:
父类静态代码块 1
父类静态成员变量
父类静态代码块 2
子类静态代码块 1
子类静态成员变量
子类静态代码块 2
new 之前
父类构造代码块 1
父类普通成员变量
父类构造代码块 2
父类构造方法
子类普通代码块 1
子类普通成员变量
子类普通代码块 2
子类构造方法
new 之后
结论:
- 父类静态代码块和静态成员变量并列优先级,按代码出现先后顺序执行。
- 子类静态代码块和静态成员变量并列优先级,按代码出现先后顺序执行。
- main方法中实例化对象(
new
)之前的代码。 - 父类构造代码块和普通成员变量并列优先级,按代码出现先后顺序执行。
- 父类构造方法。
- 子类构造代码块和普通成员变量并列优先级,按代码出现先后顺序执行。
- 子类构造方法。
- main方法中实例化对象(
new
)之前的代码。
注意,第1,2步只有在子类第一次被加载时才运行,如果创建两个对象,则第二次创建对象只执行第4,5,6,7步。
总结
在没有继承的情况下,优先级:静态代码块和静态成员变量 > 构造代码块和普通成员变量 > 构造方法。
有继承的情况下,优先级:父类静态代码块和静态成员变量 > 子类静态代码块和静态成员变量 > 父类构造代码块和普通成员变量 > 父类构造方法 > 子类构造代码块和普通成员变量 > 子类构造方法。
main方法是一个静态方法,在通过java
命令运行SubClass
时,产生的第一个事件就是试图访问SubClass.main()
,于是类加载器开始启动并找到SubClass.class
文件,对它进行加载时,发现这是一个子类(有extends关键字),于是继续加载它的父类Base
,这个过程,不管是否创建了父类对象都会进行。如果父类还有父类,那么还会继续加载,依次类推。在静态代码块和静态成员变量都加载完成后,就会执行main方法中的其他代码,如果遇到了实例化对象的代码,就会按照上述所说的优先级执行代码。
如果对你有帮助就请点个赞吧。
网友评论