一、背景

1.这节主要讲解什么情况下会触发类加载的进行呢,本文将结合代码demo谈谈几种情况,希望能帮助到正在努力学习的你们。

二、类加载时机

1.什么情况需要开始类加载过程的第一阶段:加载?Java虚拟机规范中并没有进行强制约束,这点可以交给虚拟机的具体实现来自由把握。但是对于初始化阶段,虚拟机规范则严格规定了以下几种情况必须立即对类进行初始化,如果类没有进行过初始化,则需要先触发其初始化。接下来我们就来分析下面的几种情况。

Java文件在什么时候会生成class文件 java类在什么时候加载_类加载

三、准备

1.为了验证类加载,我们先配置一个JVM参数

-XX:+TraceClassLoading 监控类的加载

2.在Idea中进行配置

Java文件在什么时候会生成class文件 java类在什么时候加载_类加载_02

四、代码实例

1.第一种情况(创建类的实例)

1.1.代码

public class DemoTest {
    public static void main(String[] args) {
        ClassLoadInstance instance = new ClassLoadInstance();
    }

    public static class ClassLoadInstance {
        static {
            System.out.println("ClassLoadInstance类初始化就会被执行!!!");
        }
        public ClassLoadInstance(){
            System.out.println("ClassLoadInstance的构造函数!!!");
        }
    }
}

1.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_初始化_03

1.3.分析

new ClassLoadInstance实例时,发现ClassLoadInstance被加载了,因此 new创建实例对象,会触发类加载进行。

2.第二种情况(访问类的静态变量)

2.1.代码

public class DemoTest {
    public static void main(String[] args) {
        System.out.println(ClassLoadStaticVariable.i);
    }

    public static class ClassLoadStaticVariable {
        static {
            System.out.println("ClassLoadStaticVariable类初始化就会被执行!!!");
        }

        public static int i = 100;

        public ClassLoadStaticVariable() {
            System.out.println("ClassLoadStaticVariable的构造函数!!!");
        }
    }
}

2.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_System_04

2.3.分析

访问类ClassLoadStaticVariable的静态变量i时,发现ClassLoadStaticVariable类被加载啦,因此访问类的静态变量会触发类加载。

注意:

访问final修饰的静态变量时,不会触发类加载,因为在编译期已经将此常量放在常量池了。

3.第三种情况(访问类的静态方法)

3.1.代码

public class DemoTest {
    public static void main(String[] args) {
        ClassLoadStaticMethod.method();
    }

    public static class ClassLoadStaticMethod {
        static {
            System.out.println("ClassLoadStaticMethod类初始化就会被执行!!!");
        }

        public static void method(){
            System.out.println("静态方法被调用");
        }

        public ClassLoadStaticMethod() {
            System.out.println("ClassLoadStaticMethod的构造函数!!!");
        }
    }
}

3.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_类加载_05

3.3.分析

访问类ClassLoadStaticMethod的静态方法method时,发现ClassLoadStaticMethod类被加载啦,因此访问类的静态方法会触发类加载。

4.第四种情况(反射)

4.1.代码

public class DemoTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("com.tydic.encryptiondemo.controller.DemoTest$ClassLoadStaticReflect");
    }

    public static class ClassLoadStaticReflect {
        static {
            System.out.println("ClassLoadStaticReflect类初始化就会被执行!!!");
        }

        public static void method() {
            System.out.println("静态方法被调用");
        }

        public ClassLoadStaticReflect() {
            System.out.println("ClassLoadStaticReflect的构造函数!!!");
        }
    }
}

4.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_java浅聊之何时类加载的情况_06

4.3.分析

反射得到类ClassLoadStaticReflect时,发现ClassLoadStaticReflect类被加载啦,因此反射会触发类加载。

5.第五种情况(当初始化一个类时,发现其父类还未初始化,则先触发父类的初始化)

5.1.代码

public class DemoTest {
    public static void main(String[] args){
        ClassLoadSub classLoadSub = new ClassLoadSub();
    }

    public static class ClassLoadSuper {
        static {
            System.out.println("ClassLoadSuper类初始化就会被执行!!!");
        }
        public static int superNum =100;
        public ClassLoadSuper() {
            System.out.println("ClassLoadSuper的构造函数!!!");
        }
    }
    public static class ClassLoadSub extends ClassLoadSuper {
        static {
            System.out.println("ClassLoadSub类初始化就会被执行!!!");
        }
        public static int subNum =100;
        public ClassLoadSub() {
            System.out.println("ClassLoadSub的构造函数!!!");
        }
    }
}

5.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_类加载_07

5.3.分析

看了运行结果,是不是发现,网上那道经典面试题(讲讲类的实例化顺序?)也很清晰啦。 先父类静态变量/静态代码块-> 再子类静态变量/静态代码块->父类构造器->子类构造器结论:

实例化子类ClassLoadSub的时候,发现父类ClassLoadSuper先被加载,因此当初始化一个类时,发现其父类还未初始化,则先触发父类的初始化

6.第六种情况(虚拟机启动时,定义了main()方法的那个类先初始化)

6.1.代码

public class DemoTest {
    public static void main(String[] args){
        ClassLoadSub classLoadSub = new ClassLoadSub();
        System.out.println(classLoadSub.subNum);
    }
    public static class ClassLoadSub {
        static {
            System.out.println("ClassLoadSub类初始化就会被执行!!!");
        }
        public static int subNum =100;
        public ClassLoadSub() {
            System.out.println("ClassLoadSub的构造函数!!!");
        }
    }
}

6.2.结果

Java文件在什么时候会生成class文件 java类在什么时候加载_类加载_08

6.3.分析

虚拟机启动时,即使有ClassLoadSub,ClassLoadSuper,ClassLoadTest等类被加载, 但ClassLoadTest最先被加载,即定义了main()方法的那个类会先触发类加载。

五、结束

就先写到这里吧!!!