类对象初始化顺序及类加载时机
类对象初始化顺序
分别在父类和子类中测试静态代码块、普通代码块、静态成员变量、构造器、静态内部类。
- 代码块及变量测试
//
class Field {
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 "";
}
}
class Father {
static {
System.out.println("父类静态代码块1");
}
private static String staticValue = Field.baseStaticFieldInit();
static {
System.out.println("父类静态代码块2");
}
{
System.out.println("父类构造代码块1");
}
private String value = Field.baseFieldInit();
{
System.out.println("父类构造代码块2");
}
Father() {
System.out.println("父类构造器");
}
}
public class Children extends Father {
static {
System.out.println("子类静态代码块1");
}
private static String staticValue = Field.staticFieldInit();
static {
System.out.println("子类静态代码块2");
}
{
System.out.println("子类构造代码块1");
}
private String value = Field.fieldInit();
{
System.out.println("子类构造代码块2");
}
public Children() {
System.out.println("子类无参构造器");
}
private static class House {
private static Children houseChildren = new Children();
}
public static void main(String[] args) {
//Children children = new Children();
//System.out.println("Children:" + children);
//System.out.println("********************************");
//
//Children children1 = new Children();
//System.out.println("Children:" + children1);
//System.out.println("********************************");
Children house = House.houseChildren;
System.out.println("ChildrenHouse:"+house);
System.out.println("*******************************");
Children chouse1 = House.houseChildren;
System.out.println("ChildrenHouse:"+chouse1);
System.out.println("*******************************");
}
}
- 测试结果
父类静态代码块1
父类静态变量
父类静态代码块2
子类静态代码块1
子类静态变量
子类静态代码块2
父类构造代码块1
父类全局变量
父类构造代码块2
父类构造器
子类构造代码块1
子类全局变量
子类构造代码块2
子类无参构造器
Children:com.cmlx.design.classtest.Children@5f5a92bb
********************************
父类构造代码块1
父类全局变量
父类构造代码块2
父类构造器
子类构造代码块1
子类全局变量
子类构造代码块2
子类无参构造器
Children:com.cmlx.design.classtest.Children@6fdb1f78
********************************
- 测试静态内部类
父类静态代码块1
父类静态变量
父类静态代码块2
子类静态代码块1
子类静态变量
子类静态代码块2
父类构造代码块1
父类全局变量
父类构造代码块2
父类构造器
子类构造代码块1
子类全局变量
子类构造代码块2
子类无参构造器
ChildrenHouse:com.cmlx.design.classtest.Children@7440e464
*******************************
ChildrenHouse:com.cmlx.design.classtest.Children@7440e464
*******************************
- 总结
(1) 静态代码块、静态成员变量只有第一次加载类时才会执行
(2) 执行顺序为:父类静态代码块及父类静态成员变量(并列优先级)—>子类静态代码块及子类静态成员变量(并列优先级)—>父类普通代码块及父类成员变量—>父类构造器—>子类普通代码块及子类成员变量—>子类构造器
(3) 静态内部类,只有在第一次调用的时候才会被初始化
java类在何时被加载
IDEA配置VM options:-XX:+TraceClassLoading 监控类的加载
新建TestController测试加载时机
@RestController
public class ClassTestController {
@RequestMapping("/newInstance")
public String newInstance(){
Father father = new Father();
return "";
}
@RequestMapping("/newChildrenInstance")
public String childrenInstance(){
Children children = new Children();
return "";
}
@RequestMapping("/staticField")
public String staticField(){
String staticValue = Children.staticValue;
return "";
}
@RequestMapping("staticMethod")
public String staticMethod(){
String bed = Children.bed();
return "";
}
@RequestMapping("classForName")
public String classForName() throws Exception {
Class.forName("com.zhixie.jvmclassload.demo.Children");
return "";
}
}
- 定义了main类,启动mian方法时该类会被加载
- 创建类的实例,即new对象的时候
(1) 创建父类的实例
(2) 创建子类的实例 - 访问类的静态方法
- 访问类的静态变量
- 反射Class.forName()
总结
- java类在以上五种情况下会被加载
- 在JVM生命周期中每个类如果存在,则不会重新加载
- 在加载子类的时候会优先其父类
- 类被加载的时候,其中的静态代码块、静态方法及静态变量也会被加载
- 在初始化某个类时,如果这个类的静态代码块、静态方法或静态变量引用到了另一类,则这个类也会被加载