Preparation:

  • Markdown authoring tools
  • Youdao Cloud Note
  • Idea development tool
  • GItHub project address

Analysis:

The whole process of class loading:

When we run the main function launcher of a class with a Java command, we first need to load the main class into the JVM through the class loader.

public class Math {
    public static final int initData = 666;
    public static User user = new User();

    public int compute() {// a method corresponds to a stack frame int a = 1; int b = 2; int c = (a + b) * 10;returnc; } public static void main(String[] args) { Math math = new Math(); math.compute(); }}Copy the code

  • The loadClass loading process has the following steps:
  • Load >> Verify >> Prepare >> Parse >> Initialize >> Use >> Uninstall
    • Load: a bytecode file is searched on the hard disk and read through IO. It is loaded only when the Class is used, such as calling the main() method of the Class, the new object, etc. During the load phase, a java.lang.Class object representing the Class is generated in memory, which acts as an access point to the various data of the Class in the method area
    • Validation: Verifies the correctness of the bytecode file
    • Preparation: Allocates memory to static variables of the class and assigns default values
    • Resolution: the replacement symbol references for direct reference to the stage will put some static methods (symbol references, such as the main () method) to replace for the pointer to the data storage, memory, or a handle, etc. (reference) directly, this is the so-called static linking process (complete) during class loading, dynamic linking is done during the program is running will use replacement for direct reference symbols.
    • Initialization: Executes a static block of code to initialize a class’s static variable to the specified value

  • After a class is loaded into the method area, it mainly contains the runtime constant pool, type information, field information, method information, class loader reference, reference to the corresponding class instance and so on.
  • Class loader reference: A reference from this class to an instance of the class loader
  • Reference to a corresponding class instance: After the class information is loaded into the method area, the class loader creates an object instance of the corresponding class type and places it in the Heap, which acts as an entry point and pointcut for developers to access the class definition in the method area.
  • ** Note: The ** main class will progressively load other classes if they are used during runtime. Classes in a JAR or WAR are not loaded all at once; they are loaded when used.
public class TestDynamicLoader {
    static {
        System.out.println("*************load TestDynamicLoad************");
    }
    public static void main(String[] args) {
        new A();
        System.out.println("*************load test************"); // B b = null; //B will not load unless new B() B = new B(); } } class A { static { System.out.println("*************load A************");
    }
    public A() {
        System.out.println("*************initial A************");
    }
}

class B {
    static {
        System.out.println("*************load B************");
    }
    public B() {
        System.out.println("*************initial B************"); }}# run result:
*************load TestDynamicLoad************
*************load A************
*************initial A************
*************load test************
*************load B************
*************initial B************
Copy the code

Class loaders and parent delegate mechanisms:

The above class loading process is mainly implemented through class loaders. There are several types of loaders in Java:

  • Bootloader: Load the core libraries that support the JVM in the JRE’s lib directory, such as rt.jar, charsets.jar, etc
  • Extension class loader: Is responsible for loading JAR classes from the Ext extension directory in the JRE’s lib directory that support the JVM
  • The application class loader is responsible for loading classes in the ClassPath path, mainly those you write yourself
  • Custom loader: loads class packages in user-defined paths
public class TestJDKClassLoader {
    public static void main(String[] args) {
        System.out.println(String.class.getClassLoader());
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
        System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());

        System.out.println();
        ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader extClassloader = appClassLoader.getParent();
        ClassLoader bootstrapLoader = extClassloader.getParent();
        System.out.println("the bootstrapLoader : " + bootstrapLoader);
        System.out.println("the extClassloader : " + extClassloader);
        System.out.println("the appClassLoader : " + appClassLoader);

        System.out.println();
        System.out.println("BootstrapLoader loads the following files:");
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println(urls[i]);
        }

        System.out.println();
        System.out.println("ExtClassloader loads the following files:");
        System.out.println(System.getProperty("java.ext.dirs"));

        System.out.println();
        System.out.println("AppClassLoader loads the following files:");
        System.out.println(System.getProperty("java.class.path")); }}# run result:
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader

the bootstrapLoader : null
the extClassloader : sun.misc.Launcher$ExtClassLoader@2d209079
the appClassLoader : sun.misc.Launcher$AppClassLoader@18b4aAC2 bootstrapLoader: File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/resources. The jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/rt. The jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/sunrsasign jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/jsse jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/jce jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/charsets. The jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/JFR jar File: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/classes extClassloader loading the following files: / Users/FWH/Library/Java/Extensions: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext: / Librar Y/Java/Extensions/Network/Library/Java/Extensions: / System/Library/Java/Extensions: / usr/lib/Java appClassLoader loading the following files: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/charsets. The jar: / Library/Java/JavaVirtualMachines / jdk1.8.0 _152. JDK/Contents/Home/jre/lib/deploy the jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre / Lib/ext/cldrdata. Jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext/DNSNS jar: / Library/jar A/JavaVirtualMachines/jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext/jaccess jar: / Library/Java/JavaVirtualMachines/jdk1.8.0 _ 152. The JDK/Contents/Home/jre/lib/ext/JFXRT jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext / localedata. Jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext/nashorn jar: / Library/Java/J AvaVirtualMachines/jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext/sunec jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. J Dk/Contents/Home/jre/lib/ext/sunjce_provider jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/li B/ext/sunpkcs11. Jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/ext/zipfs jar: / Library/Java / JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/javaws jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. Jd K/Contents/Home/jre/lib/jce jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/JFR jar: / Librar Y/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/JFXSWT jar: / Library/Java/JavaVirtualMachines/jdk1.8.0 _ 152. The JDK/Contents/Home/jre/lib/jsse jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/manageme Nt - agent. The jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/jre/lib/plugin jar: / Library/Java/JavaVirtu AlMachines/jdk1.8.0 _152. JDK/Contents/Home/jre/lib/resources. The jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Conte NTS/Home/jre/lib/rt. The jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/lib/ant - deployment headaches. Jar: / Library/jar A/JavaVirtualMachines/jdk1.8.0 _152. JDK/Contents/Home/lib/dt. The jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Conte NTS/Home/lib/deployment headaches - mx. Jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/lib/jconsole. The jar: / Library/Ja Va/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/lib/packager. The jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. Jd K/Contents/Home/lib/sa - jdi. Jar: / Library/Java/JavaVirtualMachines jdk1.8.0 _152. JDK/Contents/Home/lib/tools. The jar: / Users/FWH / A_FWH/lot/FWH - the JVM/target/classes: / Users/FWH/m2 / repository/org/projectlombok/lombok / 1.18.12 / lombok - 1.18.12. Jar: / Appl ications/IntelliJ IDEA. The app/Contents/lib/idea_rt jar: / Users/FWH/Library/Caches/JetBrains IntelliJIdea2020.1 captureAgent/debugger - agent. The jar  Disconnected from the target VM, address:'127.0.0.1:50876', transport: 'socket'

Copy the code

Class loader initialization process:

  • See the class runtime loading process diagram to see that the JVM Launcher instance Sun.misc.Launcher is created.

  • The sun.misc.Launcher initialization uses a singleton design that ensures that there is only one instance of Sun.misc.Launcher in a JVM. Within the Launcher construction method, it creates two class loaders, respectively is sun misc. The Launcher. ExtClassLoader (extension class loader) and sun. Misc. The Launcher. AppClassLoader (application class loader).

  • By default, the JVM loads our application using an instance of the AppClassLoader returned by the getClassLoader() method of the Launcher.

  • From the Java8 version:

//Launcher constructor publicLauncher() { Launcher.ExtClassLoader var1; Try {/ / tectonic extension class loader, will his father in the process of constructing the loader is set to null var1 = the Launcher. ExtClassLoader. GetExtClassLoader (); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try {// Construct the application class loader, set its parent loader to ExtClassLoader, // the loader property is AppClassLoader, We usually use this class loader to load our own written application enclosing loader. = the Launcher AppClassLoader. GetAppClassLoader (var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
    String var2 = System.getProperty("java.security.manager"); . . // Omit some unnecessary codeCopy the code

Parent delegate mechanism:

  • JVM classloaders have a parent-child hierarchy, as shown below:

  • In fact, there is a parent delegation mechanism for class loading. When a class is loaded, it first entrusts the parent loader to find the target class, and then entrusts the upper parent loader to load it. If all the parent loaders cannot find the target class in their own class loading path, they will find and load the target class in their own class loading path.

  • Our Math class, for example, the first to find the application class loader loads, the application class loader will entrust the extension class loader to load first, expand the class loader to entrust the bootstrap class loader, top the bootstrap class loader in your own class loading paths seek along while didn’t find Math class, then back down load the request of the Math class, When the extension classloader receives the reply, it loads it, searches its own class loading path, finds no Math, and returns the Math request back to the application classloader, which searches its own class loading path for Math and loads it when it finds it.

  • The parent delegate mechanism is simply that the father loads it first, and if not, the son loads it

  • The loadClass method of AppClassLoader finally calls the loadClass method of its parent class ClassLoader. The general logic of this method is as follows:

    • First, check to see if the class with the specified name has already been loaded. If it has been loaded, it does not need to be loaded again and returns directly.
    • If this class has not been loaded, then check if there is a parent loader; If there is a parent loader, it is loaded by the parent (that is, call parent-loadclass (name, false);) . Or call the bootstrap class loader to load it.
    • If neither the parent nor the Bootstrap class loader can find the specified class, the findClass method of the current class loader is called to complete the class loading.
// The loadClass method of ClassLoader implements the parent delegate mechanism. Protected Class<? > loadClass(String name, Boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// Check whether the current Class loader has loaded the Class<? > c = findLoadedClass(name);if (c == null) {
            long t0 = System.nanoTime();
            try {
                if(parent ! C = parent.loadClass(name, name, name) {// If the parent loader is not empty, delegate the parent loader to load the class.false);
                } elseC = findBootstrapClassOrNull(name); c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrownif class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass inorder // to find the class. long t1 = System.nanoTime(); C = findClass(name); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); }}ifResolveClass (c); }returnc; }}Copy the code

Why design parental delegation?

  • Sandbox security: Self-written java.lang.String.class classes are not loaded, which prevents the core API library from being tampered with
  • Avoid class reloading: When the parent has already loaded the class, there is no need for the subclassLoader to load the class again to ensure the uniqueness of the loaded class.
package java.lang;

public class String {
    public static void main(String[] args) {
        System.out.println("**************My String Class**************"); }} Error: Main method not found in java.lang.String class, define main as: Public static void main (String [] args) or deployment headaches the application class must extend deployment headaches. The application. The applicationCopy the code

Take full responsibility for the delegation mechanism

  • “Full responsibility” means that when a ClassLoder loads a class, unless another ClassLoder is displayed, the classes that the class depends on and references are also loaded by that ClassLoder.

Example of a custom class loader:

  • Custom classloaders simply inherit from the java.lang.ClassLoader class, which has two core methods,
    • LoadClass (String, Boolean) implements the parent delegate mechanism,
    • Another method is findClass. The default implementation is empty, so our custom classloader mainly overrides the findClass method.
public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\ \."."/");
            FileInputStream fis = new FileInputStream(classPath + "/" + name
                    + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            returndata; } @Override protected Class<? > findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); //defineClass converts a byte array into a Class object. This byte array is the final byte array after the Class file is read.returndefineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); }}} public static void main(String args[]) throws Exception {// initialize the custom ClassLoader first. AppClassLoader MyClassLoader classLoader = new MyClassLoader"D:/test"); / / D dish to createtestClazz = classloader.loadClass (clazz = classloader.loadclass (clazz = classloader.loadclass))"com.tuling.jvm.User1");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null); method.invoke(obj, null); System.out.println(clazz.getClassLoader().getClass().getName()); }} running results: = = = = = = = your class loaders loading method is called. = = = = = = = com tuling. JVM. MyClassLoaderTest$MyClassLoader
Copy the code
  • Note here: the main class that needs to be loaded must have object.class in the specified directory.
    • But because of the sandbox security mechanism, there will be exceptions, you need to manually determine the code, reassign.

Break the parent delegate mechanism:

  • For another example of sandbox security, try to break the parent delegate mechanism and load our own java.lang.String.class with a custom class loader
public class MyClassLoaderTest2 {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\ \."."/");
            FileInputStream fis = new FileInputStream(classPath + "/" + name
                    + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            returndata; } protected Class<? > findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name);returndefineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); }} /** * override class load method, implement own load logic, do not delegate to parent load ** @param name * @param resolve * @return* @throws ClassNotFoundException */ @Override protected Class<? > loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, checkifthe class has already been loaded Class<? > c = findLoadedClass(name);if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }

    public static void main(String args[]) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("D:/test"); Clazz = classloader.loadClass () clazz = classLoader.loadclass () clazz = classLoader.loadclass ("java.lang.String");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null); method.invoke(obj, null); System.out.println(clazz.getClassLoader().getClass().getName()); }} running results: Java. Lang. SecurityException: Prohibited package name: java.lang at java.lang.ClassLoader.preDefineClass(ClassLoader.java:659) at java.lang.ClassLoader.defineClass(ClassLoader.java:758)Copy the code

Tomcat breaks parental delegation:

  • Take Tomcat class loading as an example. What if Tomcat uses the default parent delegate class loading mechanism?

  • Let’s consider: Tomcat is a Web container, so what problem does it solve:

    1. A Web container may require two applications to be deployed, and different applications may rely on different versions of the same third-party class library. You cannot require only one copy of the same class library on the same server. Therefore, ensure that class libraries of each application are independent and isolated from each other.
    2. The same version of the same class library deployed in the same Web container can be shared. Otherwise, if the server has 10 applications, 10 copies of the same class library are loaded into the virtual machine.
    3. The Web container also has its own dependent class library, not to be confused with the application’s class library. For security reasons, the container’s libraries should be separated from the program’s libraries.
    4. The Web container needs to support JSP modification. As we know, JSP files eventually need to be compiled into class files before they can be run in the virtual machine, but it is common to modify JSPS after a program runs, and the Web container needs to support JSP modification without restarting.
  • Let’s look at our question: Does it work if Tomcat uses the default parent delegate class loading mechanism?

  • The answer is no. Why is that?

    • The first problem is that you can’t load two different versions of the same library if you use the default class loader mechanism. The default class loader only cares about your fully qualified class name and only has one copy.
    • Second, the default class loader can be implemented because its job is to ensure uniqueness.
    • The third question is the same as the first.
    • Let’s look at the fourth problem, we want to how we implement hot loading JSP file, JSP file is actually the class file, so if we change, but the class name is the same, the class loader will directly fetch the method area already exists, the modified JSP is not reloaded. So what to do? We can unmount the class loader for this JSP file directly, so you should be aware that each JSP file has a unique class loader. When a JSP file is modified, the JSP class loader is unmounted directly. Re-create the class loader and reload the JSP file.

Tomcat custom loader

  • The main class loaders for Tomcat:

    • CommonLoader: The most basic Tomcat class loader. The classes in the loading path can be accessed by the Tomcat container itself and various WebApps.
    • CatalinaLoader: a private class loader for the Tomcat container. Classes in the loading path are invisible to Webapp.
    • SharedLoader: a class loader shared by webApps. The classes in the loading path are visible to all WebApps, but not to the Tomcat container.
    • WebappClassLoader: The classes in the loading path are only visible to the current Webapp, such as loading the relevant classes in the WAR package. Each WAR package application has its own WebappClassLoader, which is isolated from each other. For example, different WAR package applications introduce different Spring versions. This way implementations can load their own versions of Spring;
  • As you can see from the delegate relationship in the figure:

    • Classes that can be loaded by CommonClassLoader can be used by CatalinaClassLoader and SharedClassLoader, thus realizing the sharing of public class libraries. Classes that CatalinaClassLoader and SharedClassLoader can load by themselves are isolated from each other. WebAppClassLoader can use classes that SharedClassLoader loads into, but the WebAppClassLoader instances are isolated from each other.
    • The scope of JasperLoader is only the one compiled by the JSP file. Class files, which are meant to be discarded: When the Web container detects that the JSP file has been modified, it replaces the current JasperLoader instance and implements hot loading of the JSP file by creating a new JSP classloader.
  • Does tomcat’s classloading mechanism violate Java’s recommended parental delegation model? The answer is: no.

    • Tomcat does not adhere to this convention for isolation. Each webappClassLoader loads a class file in its own directory and does not pass it to the parent class loader, breaking the parent delegate mechanism.
  • Simulation implementation of Tomcat webappClassLoader to load its own WAR package in the application of different versions of classes to achieve mutual coexistence and isolation

public class MyClassLoaderTest3 {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\ \."."/");
            FileInputStream fis = new FileInputStream(classPath + "/" + name
                    + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            returndata; } @Override protected Class<? > findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name);returndefineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); }} /** * override class load method, implement own load logic, do not delegate to parent load * @param name * @param resolve * @return* @throws ClassNotFoundException */ @Override protected Class<? > loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, checkifthe class has already been loaded Class<? > c = findLoadedClass(name);if (c == null) {
                    // If still not found, then invoke findClass inorder // to find the class. long t1 = System.nanoTime(); // Non-custom classes are still loaded through the parent delegateif(! name.startsWith("com.tuling.jvm")){
                        c = this.getParent().loadClass(name);
                    }else{
                        c = findClass(name);
                    }

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }

    public static void main(String args[]) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        Class clazz = classLoader.loadClass("com.tuling.jvm.User1");
        Object obj = clazz.newInstance();
        Method method= clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader());

        System.out.println();
        MyClassLoader classLoader1 = new MyClassLoader("D:/test1");
        Class clazz1 = classLoader1.loadClass("com.tuling.jvm.User1");
        Object obj1 = clazz1.newInstance();
        Method method1= clazz1.getDeclaredMethod("sout", null); method1.invoke(obj1, null); System.out.println(clazz1.getClassLoader()); }}Copy the code

* * note: within the same JVM, two of the same package name and the name of the class class objects can coexist, because their class loader can be different, so the two class object is the same, in addition to see whether the package name and class name of a class are the same, you also need to their class loader is also the same to think they are the same. 台湾国

Related knowledge:

  • javap -private Person.class
    • Decompile the output to see the contents of its bytecode files;
  • The main load is the loadClass of ClassLoad
  • By default, the JVM loads our application using an instance of the AppClassLoader returned by the getClassLoader() method of the Launcher.

Conclusion:

  • JVM content is a must for Java developers, and many low-level performance tuning applications require this knowledge to quickly locate problems and find solutions.
  • Example code -GitHub
  • Blog link: Wen Hao’s Blog
  • Wechat Official Account: