一探 Java 类加载顺序

68 阅读1分钟

懒汉式单例中有一种实现方式是通过静态内部类,利用 Java 静态内部类的加载机制,那 Java 类的加载顺序究竟是如何的呢?

结论

  • 代码执行顺序:静态代码块(仅一次) -> 非静态代码块(每次创建对象都一定会被执行) -> 构造方法
  • 类加载顺序:如果存在内部类,外部类加载时不会加载内部类,内部类被加载时优先加载外部类

实验

public class ClassLoaderStudy {  
  
    static { System.out.println("外部静态代码块"); }  
  
    { System.out.println("外部非静态代码块"); }  
  
    public ClassLoaderStudy() { System.out.println("外部无参构造方法"); }  
  
    public ClassLoaderStudy(String a) { System.out.println("外部有参构造方法"); }  
  
    public static String str = "外部静态字段";  
  
    static class StaticInner {  
        static { System.out.println("内部静态代码块"); }  
  
        public static String innerStr = "内部静态字段";  
    }  
  
    class Inner {  
        //非静态内部类不能创建静态代码块  
        { System.out.println("内部非静态代码块"); }  
  
        public Inner() { System.out.println("内部非静态无参构造方法"); }  
    }  
}  
  1. 访问静态字段

image.png

访问静态字段时,先初始化类,静态代码块会被执行

如果 ClassLoaderStudy.str 字段被 final 修饰,则『外部静态代码块』不会输出,是因为 final 修饰之后就是常量,常量是被存在静态常量池中的,不需要加载类就可以访问

  1. 其他访问情况

image.png

可见执行顺序是:

静态代码块(仅一次) -> 非静态代码块(每次创建对象都一定会被执行) -> 构造方法  

如果存在内部类,外部类加载时不会加载内部类,内部类被加载时优先加载外部类