Class lifecycle
The first five steps together are the traditional whole process of class loading
Among them, 2, 3 and 4 are collectively referred to as the link stage
Class loads and initializes
- When the virtual machine is started, the main class specified by the user is initialized, which is the class where the main method is started and executed
- When a new instruction is encountered to create a new instance of the target class, the target class of the new instruction is initialized when it is a new class
- When an instruction calling a static method is encountered, the class in which the static method is located is initialized
- When an instruction to access a static field is encountered, the class in which the static field is located is initialized
- The initialization of the child class will trigger the initialization of the parent class
- If an interface defines a default method, the initialization of the class that directly or indirectly implements the interface will trigger the initialization of the interface
- When a reflection call is made to a class using the reflection API, the class needs to be initialized. In fact, as before, the reflection call either has an instance or is a static method, which needs to be initialized
- When the MethodHandle (method pointer) instance is called for the first time, the class of the method pointed to by the MethodHandle is initialized
package jvm; import java.util.function.Function; public class HelloByteCode { public static void main(String[] args) { HelloByteCode helloByteCode = new HelloByteCode(); System.out.println(MethodHandle(new HelloByteCode()::int2Str)); } //Method pointer function private static String MethodHandle(Function<Integer,String> function){ String itoStrVal = function.apply(1); return itoStrVal; } public String int2Str(int i){ return String.valueOf(i); } }
Class may load but will not initialize
- Referencing the static field of the parent class through the child class will only trigger the initialization of the parent class, not the initialization of the child class
- Defining an object array will not trigger the initialization of this class
- Constants are stored in the constant pool of the calling class during compilation. In essence, there is no direct reference to the class that defines constants, and the class where constants are defined will not be triggered
- Getting the Class object through the Class name will not trigger Class initialization, and Hello.class will not let Hello Class initialize
- When loading the specified class through Class.forName, if the specified parameter initialize is false, class initialization will not be triggered. In fact, this parameter tells the virtual machine whether to initialize the class. Class.forName"jvm.Hello" will load the Hello class by default
- Through the default loadClass method of ClassLoader, the initialization action will not be triggered (loaded, but not initialized)
Class III loader
Class III loader:
- Start class loader (bootstrap classloader)
It is used to load some of the core jar packages and class files of the JVM. These classes are under the JDk installation folder. They are some public classes and core classes (such as rt.jar) that almost all Java programs need to use
- Extended class loader (ExtClassLoader)
As the supplementary loader of the startup class, it is responsible for loading some additional jar packages or class files to the JVM. These jar packages or class files are stored in the place specified by the JDK or JRE (extended class folder or directory). For example, the jar packages under the lab directory of the web application project are also loaded through the extended class loader
- Application class loader (AppClassLoader)
It is used to load the class files generated by our own JVM code and some other class files they depend on, as well as the jar package and class files under the class path specified by our runtime
- Custom class loader
It inherits the application class loader and is used to load class files or jar packages using custom rules
jar packages or classes within the directory loaded by the startup class loader and the extension class loader are loaded by default at JVM startup
Loader features
- Parental entrustment
When the class file or jar package needs to be loaded, first delegate the parent class loader to load the class to prevent repeated loading. If the parent class loader has been loaded out of date, it will directly pass the class file or jar package loaded by the child class loader to the child class loader
- Responsible dependence
When the class loader loads class files or jar packages, it is found that these class files and jar packages also depend on other class files or jar packages. Then they will be loaded together
- Cache load
The loaded class files or jar packages will be cached in memory. The next time you need to load the loaded class files or jar packages, you don't need to load them repeatedly, and you can get them directly from memory
Necessary and sufficient class
ClassLoder is a necessary and sufficient class in JDK. A specific implementation class is URLClassLoder, which loads classes or jar packages by specifying URL s. Other class loads are subclasses of URLClassLoder
Bootstrap classloader cannot see the specific implementation and code because it is implemented by the bottom layer of the JVM
In addition to starting the class loader, other class loaders and their parent class loaders can be obtained through the ClassLoder class loader
Gets the class loader and its class path
package jvm; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.util.List; public class JvmClassLoaderPrintPath { public static void main(String[] args) { // Start class loader URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); System.out.println("Start class loader"); for (URL url : urls) { System.out.println(" ===> " + url.toExternalForm()); } // extensions class loader printClassloader("extensions class loader ",JvmClassLoaderPrintPath.class.getClassLoader().getParent()); // Application class loader printClassloader("Application class loader",JvmClassLoaderPrintPath.class.getClassLoader()); } private static void printClassloader(String name, ClassLoader classLoader) { System.out.println(); if (null != classLoader) { System.out.println(name + " Classloader -> " + classLoader.toString()); printURLForClassloader(classLoader); } else { System.out.println(name + " Classloader -> null"); } } private static void printURLForClassloader(ClassLoader classLoader) { //Each ClassLoder contains the ucp attribute Object ucp = insightField(classLoader,"ucp"); //The ucp attribute contains the path attribute, which contains all class path s of the class loader to which the ucp belongs Object path = insightField(ucp,"path"); List paths = (List) path; for (Object p : paths) { System.out.println(" ===> " + p.toString()); } } private static Object insightField(Object obj, String fName) { Field f = null; try { if (obj instanceof URLClassLoader) { f = URLClassLoader.class.getDeclaredField(fName); } else { f = obj.getClass().getDeclaredField(fName); } f.setAccessible(true); return f.get(obj); } catch (Exception ex) { ex.printStackTrace(); } return null; } }
Output results:
Start class loader ===> file:/D:/java_oprationsystem/jre/lib/resources.jar ===> file:/D:/java_oprationsystem/jre/lib/rt.jar ===> file:/D:/java_oprationsystem/jre/lib/sunrsasign.jar ===> file:/D:/java_oprationsystem/jre/lib/jsse.jar ===> file:/D:/java_oprationsystem/jre/lib/jce.jar ===> file:/D:/java_oprationsystem/jre/lib/charsets.jar ===> file:/D:/java_oprationsystem/jre/lib/jfr.jar ===> file:/D:/java_oprationsystem/jre/classes extensions class loader Classloader -> sun.misc.Launcher$ExtClassLoader@7a92922 ===> file:/D:/java_oprationsystem/jre/lib/ext/access-bridge-64.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/cldrdata.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/dnsns.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/jaccess.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/jfxrt.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/localedata.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/nashorn.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunec.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunjce_provider.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunmscapi.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunpkcs11.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/zipfs.jar Application class loader Classloader -> sun.misc.Launcher$AppClassLoader@18b4aac2 ===> file:/D:/java_oprationsystem/jre/lib/charsets.jar ===> file:/D:/java_oprationsystem/jre/lib/deploy.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/access-bridge-64.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/cldrdata.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/dnsns.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/jaccess.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/jfxrt.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/localedata.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/nashorn.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunec.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunjce_provider.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunmscapi.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/sunpkcs11.jar ===> file:/D:/java_oprationsystem/jre/lib/ext/zipfs.jar ===> file:/D:/java_oprationsystem/jre/lib/javaws.jar ===> file:/D:/java_oprationsystem/jre/lib/jce.jar ===> file:/D:/java_oprationsystem/jre/lib/jfr.jar ===> file:/D:/java_oprationsystem/jre/lib/jfxswt.jar ===> file:/D:/java_oprationsystem/jre/lib/jsse.jar ===> file:/D:/java_oprationsystem/jre/lib/management-agent.jar ===> file:/D:/java_oprationsystem/jre/lib/plugin.jar ===> file:/D:/java_oprationsystem/jre/lib/resources.jar ===> file:/D:/java_oprationsystem/jre/lib/rt.jar ===> file:/D:/MyJavaProject/online-study/study/out/production/study/ ===> file:/D:/ideaIU-2018.3.6.win/lib/idea_rt.jar ===> file:/D:/ideaIU-2018.3.6.win/lib/rt/debugger-agent.jar
Custom ClassLoder
effect:
- Dynamic loading of classes
- Encryption protection of code
The Java source code can be obtained by decompiling the bytecode file, so the bytecode file is encrypted, and then the encrypted bytecode file is loaded through the custom classloader (in fact, the encrypted bytecode file is decrypted and converted back to the binary content of the normal bytecode file, and then transferred to the classloader for normal loading). Without affecting the normal operation of the code, Code protection and encryption can be realized
Several ways to add reference classes (add additional class files or jar packages to load classes)
1. Put it under lib/ext in JDK, or add additional parameters when compiling java files and starting Java processes - Djava.ext.dirs to specify additional paths to add to class path.
In the directories involved in both methods, class files or jar packages will be added to the loading range of the extended class loader
2. Java CP or - classpath (add the path of additional class files or jar packages to the class path of the extended class loader) or put additional class files or jar packages into the current class path
3. Custom ClassLoader loading
4. Get the ClassLoader of the currently executing class, and call the addUrl method to add a Jar or path (JDK9 is invalid)
package jvm; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class TestAddUrl { public static void main(String[] args) throws Exception { URLClassLoader classLoader = (URLClassLoader) TestAddUrl.class.getClassLoader(); String dir = "/Users/anywhere/Hello"; Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); method.setAccessible(true); URL url = new URL(dir); method.invoke(classLoader, url); Class klass = Class.forName("Hello",true, classLoader); //After JDK9, the application class loader and extension class loader are at the same level as URLClassLoder, and there is no inheritance relationship. At this time, URLClassLoder cannot be obtained through the class loader of the current class. You can use the following methods //Class klass2 = Class.forName("Hello",true, new URLClassLoader(new URL[]{new URL(dir)})); Object obj = klass.newInstance(); Method hello = klass.getDeclaredMethod("hello"); hello.invoke(obj); } }