The life cycle of a class in a JVM includes seven stages: loading, preparing, validating, parsing, initializing, using, and unloading. Among them, preparation, verification and resolution are classified as connection stage.
Load
What the jvm does at this stage
- Get the binary byte stream of the class by the class name
- Convert the static storage structure represented by this byte stream to the runtime data structure of the method area
- Generate a java.lang.class object representing the class in the heap as the access to the class's data in the method area
At this stage, developers can control the acquisition of binary byte stream, that is, they can do their own customized operations through a custom classloader.
Verification
As the name implies, verify the correctness of the loaded class.
- File format validation: verify that the byte stream conforms to the specification of Class file format; for example, whether it starts with 0xCAFEBABE
- Metadata validation: semantic analysis of the information described by bytecode to ensure that the information described meets the requirements of Java language specification
- Bytecode verification: through the analysis of data flow and control flow, it is determined that the program semantics are legal and logical.
- Symbol reference validation: ensure that parsing actions can be performed correctly
Get ready
Allocates memory for static variables of a class and initializes it to the default value
- Allocate only static variable memory
- The initialization default value is the default value of the type (i.e. int:0, boolean:false...), not the initial value of the code display setting
- If it is a variable decorated with final static, it will be assigned to the initial value in the code (that is, final static int val=3, when val is assigned to 3 instead of 0).
analysis
Converting a symbol reference in a class to a direct reference is a set of symbols that describe the target (for example, ArrayList). A direct reference is a pointer directly to a target, a relative offset, or a handle that is indirectly located to the target.
Initialization
Class variable initialization
- Initialize when defining class variables
- Static block initialization
Trigger class initialization scenario
- Create a class instance, that is, a new object
- Accessing static variables
- Accessing static methods
- Reflection call (i.e. Class.forName("com.xxx.Obj"), obj class is initialized)
- When a subclass is initialized, the parent class is initialized
Class loader
- BootStrap ClassLoader: it is responsible for loading class libraries that can be recognized by the jvm under jrelib or under the path specified by the - Xbootclasspath parameter. Developers can't use it directly
- Extension ClassLoader: sun.misc.Launcher$ExtClassLoader, which is responsible for loading all class libraries in the jrelibext directory or in the path specified by the java.ext.dirs system variable. Developers can use it directly.
- Application ClassLoader: sun.misc.Launcher$AppClassLoader, which is responsible for loading the class specified by the user ClassPath. Developers can use it directly
- Custom ClassLoader: user can customize class loader
Parents Delegation Model
When a class loader needs to load a class, it will delegate the task to the parent class loader. It will start the class loader from the top to the top in turn. If the parent cannot load, it will handle the loading by itself. The advantage of the parental delegation model is that there is only one class in the same class environment. That is to say, the condition for judging whether the same class is in the JVM is whether the same class loader is the same as the class itself. Code example:
public class ClassLoaderTest { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { // Use ClassLoaderTest's classloader to load this class Object obj1 = ClassLoaderTest.class.getClassLoader().loadClass("com.ognice.ClassLoaderTest").newInstance(); System.out.println(obj1.getClass().getClassLoader()); System.out.println(obj1 instanceof ClassLoaderTest); // Use custom class loader to load this class ClassLoader customClassLoader = new ClassLoader() { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { System.out.println("custom classloader loading " + name); String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream stream = getClass().getResourceAsStream(fileName); if (stream == null) { return super.loadClass(name); } try { byte[] b = new byte[stream.available()]; stream.read(b); return defineClass(name, b, 0, b.length); } catch (IOException e) { e.printStackTrace(); } // Parent search class return super.loadClass(name); } }; Object obj2 = customClassLoader.loadClass("com.ognice.ClassLoaderTest").newInstance(); System.out.println(obj2.getClass().getClassLoader()); System.out.println(obj2 instanceof ClassLoaderTest); } }
results of enforcement
sun.misc.Launcher$AppClassLoader@18b4aac2 true custom classloader loading com.ognice.ClassLoaderTest custom classloader loading java.lang.Object custom classloader loading java.lang.ClassLoader custom classloader loading com.ognice.ClassLoaderTest$1 com.ognice.ClassLoaderTest$1@277c0f21 false