7.2Loading timing of jvm class

Class loading timing–based on jdk1.8

  • 1. Under what circumstances will a class be loaded?
    • 1. Encounter the following 4 bytecode instructions
    • 2. Use reflection to make a reflective call to a certain type
    • 3. When initializing a class, if it is found that its parent class has not been initialized, you need to trigger the initialization of its parent class first.
    • 4. When jvm is running, first initialize the main class where the main method is located.
    • 5.Dynamic language support was added in jdk7. When a method handle MethodHandle is parsed into the following method handle and the corresponding type is not initialized
    • 6. The implementation class of the interface with the default method is initialized
  • 2. Test code
    • Summarize
  • 3. Give an example of passive reference (the test will not be initialized, but it does not mean that the class will not go through the loading, verification, and preparation stages)
  • 4. Questions

1. Under what circumstances will a class be loaded?

 The "JVM Virtual Machine Specification" does not clearly state when a class will be loaded. This process is left to the specific implementation of the virtual machine, but it clearly states when a class will be initialized. The life cycle of the class is:
![](https://img-blog.csdnimg.cn/d5ab634045754a12a9fad7aabb2d255f.png#pic_center)
It can be seen that the class is loaded before the class initialization, and the possible loading timing of the class can be deduced from this.
In the "Java Virtual Machine Specification", it is strictly stipulated that there are and only the following six situations where the class must be "initialized" immediately (provided that it has not been initialized before)

1. Encounter the following 4 bytecode instructions

 a.new - the most common new object
b.getstatic-Get the static attributes of a class
c.putstatic-Set static properties of a class
d.invokestatic-Invoke a static method of a class

2. Use reflection to make a reflective call to a certain type

3. When initializing a class, if it is found that its parent class has not been initialized, you need to trigger the initialization of its parent class first

4. When jvm is running, first initialize the main class where the main method is located

Dynamic language support was added in 5.jdk7. When a method handle MethodHandle is parsed into the following method handle and the corresponding type is not initialized

a. REF_getStatic
b. REF_putStatic
c. REF_invokeStatic
d. REF_newInvokeSpecial

6. The implementation class of the interface with the default method is initialized

2. Test code

public class C07_01ClassInitWays {<!-- -->
    static {<!-- -->
        System.out.println("4.main->To class initialization");
    }
    public static void main(String[] args) throws Throwable{<!-- -->
        //0 new omitted
        //1. Get static value
       int anInt = InitClass01_ReadStaticField.anInt;
        //2. Call a static method of a type
        InitClass02_invokeStaticMethod.getNum();
        //3.Reflection
        testReflect();
        //4.main-executed from the beginning
        //5.MethodHandle and specific method handle
        testMethodHandle();
        //6. Interface but has default method execution
        testDefaultMethod();
        Class<InitClass06_InterDefaultMethod> initClass06_interDefaultMethodClass = InitClass06_InterDefaultMethod.class;
    }
    public static void testReflect() throws NoSuchFieldException, IllegalAccessException {<!-- -->
        Class<InitClass03_ByReflect> aClass = InitClass03_ByReflect.class;
        Field field = aClass.getDeclaredField("num");
        field.setAccessible(true);
        Object value = field.get(null);//Get the static property null, you can have no object
    }
    public static void testMethodHandle() throws Throwable {<!-- -->
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(void.class);
        MethodHandle methodHandle = lookup.findStatic(InitClass05_MethodHandle.class, "staticMethod", methodType);
        MethodHandleInfo info = lookup.revealDirect(methodHandle);

        System.out.println("The bytecode corresponds to the constant:" + info.getReferenceKind() + "The constant corresponds to the bytecode:" + MethodHandleInfo.referenceKindToString(info.getReferenceKind()));

        methodHandle.invokeExact();
    }
    public static void testDefaultMethod() {<!-- -->
        InitClass06_ClassImplInterface obj= new InitClass06_ClassImplInterface();
        obj.getA();
    }
}
//1.static field
class InitClass01_ReadStaticField {<!-- -->
    static {<!-- -->
        System.out.println("1. Read static field->initialize class");
    }
    public static int anInt = 10;
}
//2.static method
class InitClass02_invokeStaticMethod {<!-- -->
    static {<!-- -->
        System.out.println("2. Call static method->initialize class");
    }
    public static int getNum(){<!-- -->
        return 11;
    }
}
//3.Reflection
class InitClass03_ByReflect {<!-- -->
    static {<!-- -->
        System.out.println("3. Reflection causes class initialization");
    }
    public static int num = 12;
}
//5.MethodHandle
class InitClass05_MethodHandle {<!-- -->
    static {<!-- -->
        System.out.println("5.MethodHandle is resolved to a specific method handle causing class initialization");
    }
    public static void staticMethod() {<!-- -->
        //System.out.println("The static method specified by MethodHandle is executed");
    }
}
//6.interface default method
interface InitClass06_InterDefaultMethod {<!-- -->
  default void getA(){<!-- -->
      System.out.println("6.Interface default method The interface is initialized");
    }
}
class InitClass06_ClassImplInterface implements InitClass06_InterDefaultMethod{<!-- -->
    static {<!-- -->
        System.out.println("The class that implements the interface is initialized");
    }
}
//result:
4.main->initialize class
1. Read static field->to class initialization
2. Call static method->initialize class
3. Reflection causes class initialization
Bytecode corresponding constant: 6 Constant corresponding bytecode: invokeStatic
5.MethodHandle resolves to a specific method handle causing class initialization
The class that implements the interface is initialized
6. Interface default method The interface is initialized

Summary

 The above are several situations that will definitely lead to class initialization, which will definitely lead to class loading-active reference. But classes can be loaded without initialization -.

3. Examples of passive references (the test will not be initialized, but it does not mean that the class will not go through the loading, verification, and preparation phases)

public class C07_02ClassNoInitWays {<!-- -->
    public static void main(String[] args) throws ClassNotFoundException {<!-- -->
        testSupStaticField();
        testArr();
        testFinalStaticField();
        System.out.println("call new");
        testFinalStaticFieldNew();
        testClassObj();
    }

    public static void testSupStaticField() {<!-- -->
        int num = B.num;//It will only cause the class where the num field is located to be initialized, but b will not
    }

    public static void testArr() {<!-- -->
        C[] arr = new C[10];
    }

    public static void testFinalStaticField() {<!-- -->
        int dNum = D.DNum;
        String dw = D.DW;
    }

    public static void testFinalStaticFieldNew() {<!-- -->
        String dnew = D.DNEW;

    }
    //Will not cause E to be initialized
    public static void testClassObj() throws ClassNotFoundException {<!-- -->
        //1. Get the class object
        Class<E> eClass = E.class;
        //2.Class.forName()-initialize = false
        Class<E> aClass =(Class<E>) Class.forName("com.c7_classload.E",false,ClassLoader.getSystemClassLoader());
        //3.ClassLoader.LoadClass()
        Class<?> aClass1 = ClassLoader.getSystemClassLoader().loadClass("com.c7_classload.E");

    }
}

class A {<!-- -->
    public static int num = 10;

    static {<!-- -->
        System.out.println("A initialization");
    }
}

class B extends A {<!-- -->
    static {<!-- -->
        System.out.println("B initialization");
    }
}

class C {<!-- -->
    static {<!-- -->
        System.out.println("C initialization");
    }
}

class D {<!-- -->
    //It must be a constant - no new is needed
    public static final int DNum = 12;
    public static final String DW = "DW";
    //will be initialized
    public static final String DNEW = new String("DW");

    static {<!-- -->
        System.out.println("D initialization");
    }
}
class E {<!-- -->
    static {<!-- -->
        System.out.println("E initialization");
    }
}
result:
A initialization
call new
D initialization

4. Questions

For an interface with default methods, will the interface be initialized when the implemented class calls a non-default method? Is it necessary to initialize the interface at this time?