Preface
Everyone should know that when a Java project is started, the JVM will find the main method, and load the class file and the class file in the referenced jar package according to the calls between the objects (the steps are divided into loading, verification, preparation, parsing, initialization, use and unloading). The method area opens up memory to store the class's runtime data structure (including static variables, static methods, constant pools, class structures, etc.), and at the same time, the corresponding Class object is generated in the heap to point to the corresponding class runtime data structure in the method area.
To summarize in the simplest sentence, the process of class loading is that the JVM reads the class bytecode file through IO streams based on the path of the required class file, and injects it into memory through a series of parsing and initialization steps. Class loaders in java include: BootstrapClassLoader (top layer), ExtClassLoader, AppClassLoader, and user-defined ClassLoader (bottom layer). For different types of jar packages (or class files), JVM will have different types of class loaders to load.
The corresponding relationship is as follows:
BootstrapClassLoader is used to load the classes required for JVM running:
JAVA_HOME/jre/lib/resources.jar: JAVA_HOME/jre/lib/rt.jar: JAVA_HOME/jre/lib/sunrasign.jar: JAVA_HOME/jre/lib/jsse.jar: JAVA_HOME/jre/lib/jce.jar: JAVA_HOME/jre/lib/charsets.jar: JAVA_HOME/jre/lib/jfr.jar: JAVA_HOME/jre/lib/classes
ExtClassLoader is used to load extension classes:
../Java/Extensions: ../JAVA_HOME/jre/lib/ext: ../Library/Java/Extensions:/Network/Library/Java/Extensions: ../System/Library/Java/Extensions: ../lib/java
AppClassLoader is used to load the classes created under ClassPath and classes referenced in the jar package in our project.
The entire class loading is loaded through a mechanism called parent delegation.
For example, a class is loaded by the lowest level loader (user-defined ClassLoader). This loader will first call the previous level loader (AppClassLoader) for loading, and the AppClassLoader will continue to be handed over to the upper level (ExtClassLoader) for loading until the BootstrapClassLoader. If the classpath loaded by BootstrapClassLoader cannot find this class, it will be handed over to the loader (ExtClassLoader) of the next layer for loading. If this class cannot be found, it will continue to be handed over to the next layer (AppClassLoader) for loading. And so on, if the user-defined ClassLoader cannot find this class, the program will throw a ClassNotFoundError.
The entire loading process is shown as follows:
(The image is quoted from: https://www.cnblogs.com/xing901022/p/4574961.html)
The source code tracking of the class loading source is as follows (the source code has been appropriately simplified here). Readers can click on the source code to view:
package java.lang.ClassLoader;import ...... protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, find in the virtual machine memory whether this class has been loaded... The main problem with class cache lies! ! ! Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //Let the previous layer loader load first c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { //Calendar the findClass method implemented by this loader to load c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } }You can fully appreciate the process of parent delegation mechanism in the source code, and the three most important sentences of code have been marked:
If the user needs a custom loader and load the class file of the specified path, he needs to inherit the ClassLoader and implement the findClass(String name) method. As an example:
package com.linuxidc.utils;import java.io.ByteArrayOutputStream;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;public class ServiceClassLoader extends ClassLoader{ private String classPath; public ServiceClassLoader(String classPath) { this.classPath = classPath; } /** * Rewrite the findClass method of the parent class. The loadClass of the parent class will call this method */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = null; byte[] classData = getClassData(name); if (classData!=null) { c = defineClass(name, classData, 0, classData.length); }else { throw new ClassNotFoundException(); } return c; } // Read the class file through the IO stream and convert it into a byte array private byte[] getClassData(String name) { String path = classPath + "/"+ name.replace('.', '/') + ".class"; InputStream iStream = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { iStream = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = iStream.read(buffer))!=-1) { byteArrayOutputStream.write(buffer, 0, temp); } if (byteArrayOutputStream!=null) { return byteArrayOutputStream.toByteArray(); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (iStream!=null) { iStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (byteArrayOutputStream!=null) { byteArrayOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; }}The code for using the class loader is as follows:
ServiceClassLoader serviceClassLoader = new ServiceClassLoader("c:/myclass");Czlass<?> c = ServiceClassLoader.loadClass("com.linuxidc.service.Myclass");If you use the same ServiceClassLoader object to load the same Class file multiple times, the Class object after each load is the same! However, if new different custom ClassLoader loads the same Class file, a different Class object will be returned each time.
Note: The Class file you want to load cannot be placed in the classpath directory and any subdirectories, otherwise it will be loaded first by the AppClassLoader (this is because the class loading adopts the parent delegation mechanism, and the AppClassLoader can load all class files under the classpath). Each time, the same AppClassLoader is loaded, so there will be class caching problems.
This solves the problem of directly using reflection when JVM class loads.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.