ClassLoader is a Java class loader used to load class files into the JVM. Here’s an overview of Java class loaders.

First, the loader provided by Java

Java provides three classLoaders:

1, BootstrapClassLoader

Rt. jar, resources. Jar, charsets. Jar, etc. in %JRE_HOME%\lib of the environment variable.

Add the -xbootclasspath parameter to the Bootstrap path list when the JVM starts. This parameter can be used in two ways:

1), -xbootclasSPath /a:{manually specify the path}, and load the corresponding path after the default path of Bootstrap. In other words, if there are duplicate classes, the classes in the default path of Bootstrap will take precedence. For example:

java -Xbootclasspath/a:D:\test\Test.jar

2), -xbootclasspath /p: {manually specify the path} to load the corresponding path after the default path of Bootstrap.

java -Xbootclasspath/p:D:\test\Test.jar

2, the Extention of this

Extend the class loader to load the class file in the %JRE_HOME%\lib\ext directory of the environment variable

The loader can also change the loading behavior at JVM startup with a parameter called -d java.ext.dirs=, which replaces the directory of files loaded by the Java extension classloader.

Note that this parameter is a replacement, not an append, because there is only one loading path for this loader, that is, %JRE_HOME%\lib\ext is the default path for the extension classloader. If we use -djava.ext. dirs=d:/test at startup, Java will no longer load files in the %JRE_HOME%\lib\ext path.

3, AppclassLoader

The -classpath parameter in the JVM startup command can be used to specify the absolute path, relative path, environment variables, etc. For example:

The Java classpath – the classpath % %

Second, the relationship between various loaders

From the loading relation:

BootstrapClassLoader is the parent loader of Extention ClassLoader.

ExtentionClassLoader is the parent loader of AppclassLoader.

Note that the parent loader is not a parent class in the Java language, just a logical one.

From the Java language perspective:

1. The corresponding Java class of ExtentionClassLoader is ExtClassLoader, and its parent class is java.net.URLClassLoader.

2. AppclassLoader’s Java class is AppclassLoader, and its parent class is java.net.URLClassLoader, same as ExtClassLoader.

3, BootstrapClassLoader is written in C++, there is no corresponding Java class, of course, can not become someone else’s parent class.

The ClassLoader class has the getParent() method to get the parent of a loader that is specified when it is initialized.

AppclassLoader uses the getParent() method to get an ExtClassLoader.

The ExtClassLoader returns null using the getParent() method.

If we define a custom loader, we tend to inherit the ClassLoader class, and the default parent loader is AppClassLoader.

Third, the loading sequence of the loader

Loaders are loaded in the following order at JVM startup:

1, BootstrapClassLoader

2, ExtentionClassLoader

3, AppclassLoader

For this loading order, refer to the Sun.misc.Launcher class, which initializes each loader at JVM startup with the following code:

/** *This class is used by the system to launch the main application. Launcher */

public class Launcher {

   private static URLStreamHandlerFactory factory = new Factory();

   private static Launcher launcher = new Launcher();

   private static String bootClassPath =

       System.getProperty("sun.boot.class.path");

 

   public static Launcher getLauncher(a) {

       return launcher;

    }

 

   private ClassLoader loader;

 

   public Launcher(a) {

       // Create the extension class loader

       ClassLoader extcl;

       try {

           extcl = ExtClassLoader.getExtClassLoader();

       } catch (IOException e) {

           throw new InternalError(

                "Could not createextension class loader", e);

       }

 

       // Now create the class loader to use to launch the application

       try {

           loader = AppClassLoader.getAppClassLoader(extcl);

       } catch (IOException e) {

           throw new InternalError(

                "Could not create applicationclass loader", e);

       }

 

       // Also set the context class loader for the primordial thread.

       Thread.currentThread().setContextClassLoader(loader);

 

       // Finally, install a security manager if requested

       String s = System.getProperty("java.security.manager");

       if(s ! =null) {

           SecurityManager sm = null;

           if ("".equals(s) || "default".equals(s)) {

                sm = newjava.lang.SecurityManager();

           } else {

                try {

                    sm =(SecurityManager)loader.loadClass(s).newInstance();

                } catch (IllegalAccessExceptione) {

                } catch (InstantiationExceptione) {

                } catch (ClassNotFoundExceptione) {

                } catch (ClassCastException e){

                }

           }

           if(sm ! =null) {

                System.setSecurityManager(sm);

           } else {

                throw new InternalError(

                    "Could not createSecurityManager: "+ s); }}}... There's a lot more}Copy the code

The Bootstrap ClassLoader is loaded before initializing the ExtClassLoader and then initializing the AppClassLoader. The Bootstrap ClassLoader is loaded before initializing the ExtClassLoader.

private static String bootClassPath =

       System.getProperty("sun.boot.class.path");
Copy the code

This is the Bootstrap ClassLoader class loading path, you can write a code to see what this path is:

System.out.println(System.getProperty("sun.boot.class.path"));
Copy the code

Output result:

C:\ProgramFiles\Java\jre7\lib\resources.jar;

C:\Program Files\Java\jre7\lib\rt.jar;

C:\ProgramFiles\Java\jre7\lib\sunrsasign.jar;

C:\Program Files\Java\jre7\lib\jsse.jar;

C:\Program Files\Java\jre7\lib\jce.jar;

C:\ProgramFiles\Java\jre7\lib\charsets.jar;

C:\Program Files\Java\jre7\lib\jfr.jar;

C:\Program Files\Java\jre7\classes

The actual output is no line breaks, so I put a line break at the semicolon.

Launcher class load ExtClassLoader and AppClassLoader these two classes are also defined in the Launcher, source can also look at

ExtClassLoader class definition:

/* * The class loader used for loading installed extensions. */
    static class ExtClassLoader extends URLClassLoader {

        static {
            ClassLoader.registerAsParallelCapable();
        }

        /** * create an ExtClassLoader. The ExtClassLoader is created * within a context that limits which files it can read */
        public static ExtClassLoader getExtClassLoader(a) throws IOException
        {
            final File[] dirs = getExtDirs();

            try {
                // Prior implementations of this doPrivileged() block supplied
                // aa synthesized ACC via a call to the private method
                // ExtClassLoader.getContext().

                return AccessController.doPrivileged(
                    new PrivilegedExceptionAction<ExtClassLoader>() {
                        public ExtClassLoader run(a) throws IOException {
                            int len = dirs.length;
                            for (int i = 0; i < len; i++) {
                                MetaIndex.registerDirectory(dirs[i]);
                            }
                            return newExtClassLoader(dirs); }}); }catch (java.security.PrivilegedActionException e) {
                throw(IOException) e.getException(); }}void addExtURL(URL url) {
            super.addURL(url);
        }

        /* * Creates a new ExtClassLoader for the specified directories. */
        public ExtClassLoader(File[] dirs) throws IOException {
            super(getExtURLs(dirs), null, factory);
            SharedSecrets.getJavaNetAccess().
                getURLClassPath(this).initLookupCache(this);
        }

        private static File[] getExtDirs() {
            String s = System.getProperty("java.ext.dirs");
            File[] dirs;
            if(s ! =null) {
                StringTokenizer st =
                    new StringTokenizer(s, File.pathSeparator);
                int count = st.countTokens();
                dirs = new File[count];
                for (int i = 0; i < count; i++) {
                    dirs[i] = newFile(st.nextToken()); }}else {
                dirs = new File[0];
            }
            return dirs;
        }

        private static URL[] getExtURLs(File[] dirs) throws IOException {
            Vector<URL> urls = new Vector<URL>();
            for (int i = 0; i < dirs.length; i++) {
                String[] files = dirs[i].list();
                if(files ! =null) {
                    for (int j = 0; j < files.length; j++) {
                        if(! files[j].equals("meta-index")) {
                            File f = new File(dirs[i], files[j]);
                            urls.add(getFileURL(f));
                        }
                    }
                }
            }
            URL[] ua = new URL[urls.size()];
            urls.copyInto(ua);
            return ua;
        }

        /* * Searches the installed extension directories for the specified * library name. For each extension directory, we first look for * the native library in the subdirectory whose name is the value * of the system property os.arch. Failing that, we * look in the extension directory itself. */
        public String findLibrary(String name) {
            name = System.mapLibraryName(name);
            URL[] urls = super.getURLs();
            File prevDir = null;
            for (int i = 0; i < urls.length; i++) {
                // Get the ext directory from the URL
                File dir = new File(urls[i].getPath()).getParentFile();
                if(dir ! =null && !dir.equals(prevDir)) {
                    // Look in architecture-specific subdirectory first
                    // Read from the saved system properties to avoid deadlock
                    String arch = VM.getSavedProperty("os.arch");
                    if(arch ! =null) {
                        File file = new File(new File(dir, arch), name);
                        if (file.exists()) {
                            returnfile.getAbsolutePath(); }}// Then check the extension directory
                    File file = new File(dir, name);
                    if (file.exists()) {
                        return file.getAbsolutePath();
                    }
                }
                prevDir = dir;
            }
            return null;
        }

        private static AccessControlContext getContext(File[] dirs)
            throws IOException
        {
            PathPermissions perms =
                new PathPermissions(dirs);

            ProtectionDomain domain = new ProtectionDomain(
                new CodeSource(perms.getCodeBase(),
                    (java.security.cert.Certificate[]) null),
                perms);

            AccessControlContext acc =
                new AccessControlContext(new ProtectionDomain[] { domain });

            returnacc; }}Copy the code

The getExtDirs() method returns the java.ext.dirs address, which can also be printed:

System.out.println(System.getProperty("java.ext.dirs"));
Copy the code

Output results:

C:\Program Files\Java\jre7\lib\ext;

C:\Windows\Sun\Java\lib\ext

AppClassLoader class definition:

/** * The class loader used for loading from java.class.path. * runs in a restricted security context. */
    static class AppClassLoader extends URLClassLoader {

        static {
            ClassLoader.registerAsParallelCapable();
        }

        public static ClassLoader getAppClassLoader(final ClassLoader extcl)
            throws IOException
        {
            final String s = System.getProperty("java.class.path");
            final File[] path = (s == null)?new File[0] : getClassPath(s);

            // Note: on bugid 4256530
            // Prior implementations of this doPrivileged() block supplied
            // a rather restrictive ACC via a call to the private method
            // AppClassLoader.getContext(). This proved overly restrictive
            // when loading classes. Specifically it prevent
            // accessClassInPackage.sun.* grants from being honored.
            //
            return AccessController.doPrivileged(
                new PrivilegedAction<AppClassLoader>() {
                    public AppClassLoader run(a) {
                    URL[] urls =
                        (s == null)?new URL[0] : pathToURLs(path);
                    return newAppClassLoader(urls, extcl); }}); }final URLClassPath ucp;

        /* * Creates a new AppClassLoader */
        AppClassLoader(URL[] urls, ClassLoader parent) {
            super(urls, parent, factory);
            ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
            ucp.initLookupCache(this);
        }

        /** * Override loadClass so we can checkPackageAccess. */
        publicClass<? > loadClass(String name,boolean resolve)
            throws ClassNotFoundException
        {
            int i = name.lastIndexOf('. ');
            if(i ! = -1) {
                SecurityManager sm = System.getSecurityManager();
                if(sm ! =null) {
                    sm.checkPackageAccess(name.substring(0, i)); }}if (ucp.knownToNotExist(name)) {
                // The class of the given name is not found in the parent
                // class loader as well as its local URLClassPath.
                // Check if this class has already been defined dynamically;
                // if so, return the loaded class; otherwise, skip the parent
                // delegation and findClass.Class<? > c = findLoadedClass(name);if(c ! =null) {
                    if (resolve) {
                        resolveClass(c);
                    }
                    return c;
                }
                throw new ClassNotFoundException(name);
            }

            return (super.loadClass(name, resolve));
        }

        /** * allow any classes loaded from classpath to exit the VM. */
        protected PermissionCollection getPermissions(CodeSource codesource)
        {
            PermissionCollection perms = super.getPermissions(codesource);
            perms.add(new RuntimePermission("exitVM"));
            return perms;
        }

        /**
         * This class loader supports dynamic additions to the class path
         * at runtime.
         *
         * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch
         */
        private void appendToClassPathForInstrumentation(String path) {
            assert(Thread.holdsLock(this));

            // addURL is a no-op if path already contains the URL
            super.addURL( getFileURL(new File(path)) );
        }

        /** * create a context that can read any directories (recursively) * mentioned in the class path. In the case of a jar, it has to * be the directory containing the jar, not just the jar, as jar * files might refer to other jar files. */

        private static AccessControlContext getContext(File[] cp)
            throws java.net.MalformedURLException
        {
            PathPermissions perms =
                new PathPermissions(cp);

            ProtectionDomain domain =
                new ProtectionDomain(new CodeSource(perms.getCodeBase(),
                    (java.security.cert.Certificate[]) null),
                perms);

            AccessControlContext acc =
                new AccessControlContext(new ProtectionDomain[] { domain });

            returnacc; }}Copy the code

In the getAppClassLoader() method of this class, we get the java.class.path argument, which we can print out:

System.out.println(System.getProperty("java.class.path"));
Copy the code

Output result:

D:\workspace\test\bin;

C: \ Users \ lk \ Downloads \ asm 4.2 jar;

C: \ Users \ lk \ Desktop \ dubbo – 2.8.3.2 jar;

C: \ Users, lk, Downloads, additional – 2.2. Jar;

C: \ Users, lk, Downloads, netty – 3.2.5. Final. The jar

These are all directories and JARS that I have configured in my classpath.

Fourth, find the class and parent delegate

When a Java loader looks for or loads a class, it needs to confirm that the class is already loaded. If it is already loaded, it does not load again.

The way a class loader looks up a class is called the parent delegate mode, and the basic method is:

1, check the cache first, verify whether the class is loaded, if not in the cache query to the delegate parent loader.

2, the parent loader receives the delegate and also checks its own cache if there is no delegate up again.

3. If the top-level BootstrapClassLoader does not find the class in the cache, the BootstrapClassLoader looks for the class from its own loading path. If it does not find the class, the BootstrapClassLoader returns to the next loader.

4. The next level loader also looks for the class in its own load path, and if it does not find it returns to the next level until it returns to the original loader.

In simple terms, it looks up the cache from the bottom and scans the path from the top down. If it is found at any of these steps that the class has been loaded, it is immediately returned without further lookups.

A diagram of the process would look like this:

Figure 1

The order of search is from ① to ⑥ on the graph

Fifth, custom ClassLoader

A user-defined ClassLoader class must meet the following requirements:

1, inherit java.lang.ClassLoader, or inherit one of its subclasses such as java.net.URLClassLoader.

2, override either the findClass() method or the loadClass() method, which findClass() is called when the loadClass() method of the loader is called.

FindClass () uses the defineClass() method. This method does not need to be implemented by the parent ClassLoader. The parameters of this method are explained in more detail in a later example.

To use a custom ClassLoader class, the following steps are generally required:

1. Initialize the ClassLoader.

2. Call the loadClass() method of ClassLoader to load the target class. The parameter is String and contains the package name and class name of the target class, excluding “. When you call this method, you call the findClass() method you wrote in the loader.

3. Use class.newinstance () of the loaded class to form an object to the target class.

Here’s an example

Class = target Class = target Class

package classloader;

public class Test {

    public void hello(a) {
        System.out.println("hello world"); }}Copy the code

The following is the focus, custom ClassLoader:

package classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader extends ClassLoader {

    private String myClassPath;

    public MyClassLoader(String path) {
        myClassPath = path;
    }

    @Override
    protectedClass<? > findClass(String name)throws ClassNotFoundException {

        File file = new File(myClassPath, name+".class");

        try {
            FileInputStream is = new FileInputStream(file);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while((len = is.read()) ! = -1) { bos.write(len); }}catch (IOException e) {
                e.printStackTrace();
            }

            byte[] data = bos.toByteArray();
            is.close();
            bos.close();

            return defineClass(name, data, 0, data.length, null);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return super.findClass(name); }}Copy the code

A custom ClassLoader can inherit the ClassLoader class and override the findClass(String Name) method, which basically prepares for the final call to the defineClass() method.

The defineClass() method has multiple overloaded methods in its parent class, and they end up calling a defineClass() method with five arguments:

1, file name (with “.class “)

2. Binary array of class file contents

3. The index in a binary array that represents the beginning of class data

Class Specifies the length of the binary data

5, protectionDomain, which identifies the permission information of the encapsulation domain of the class, can not (this example does not), refer to the JDK documentation for details.

From the definition of this method, it seems to be possible to support a long binary array. All the developer has to do is specify the start index and length of the array representing the target Class, and Java can extract the target Class information from it and load it, but I can’t think of a scenario where this can be used. (In this case, the binary array comes from the full class file, so the starting subscript is 0, and Java needs to read the entire array.)

Finally, write a class using our custom loader:

package classloader;

import java.lang.reflect.Method;

public class ClassLoaderTest {

    public static void main(String[] args) {

        try {

            // Initialize the loader
            MyClassLoader myLoader = new MyClassLoader("D:\\workspace\\test\\bin");

            / / load the class
            Class c = myLoader.loadClass("classloader.Test");

            / / verification
            Object obj = c.newInstance();
            Method method = c.getDeclaredMethod("hello".null);
            method.invoke(obj, null);

        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

Running the class, the console prints Hello World, indicating that the target class loaded successfully.

The loadClass() method is defined in the ClassLoader class with the following code:

protectedClass<? > loadClass(String name,boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loadedClass<? > c = findLoadedClass(name);if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if(parent ! =null) {
                        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) {
                    // 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 statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); }}if (resolve) {
                resolveClass(c);
            }
            returnc; }}Copy the code

As you can see, the method first checks to see if the class is loaded, and if it is not, the parent loader loads it first. If there is no parent loader, use Bootstrap ClassLoader to load. If the parent loader fails to load the class, the findClass() method is called to load it.

Reload class, hot replace

First, the basics:

1. Java currently has no specific API for unloading classes loaded in the JVM.

2. To unload a class in the JVM, all the objects of the class need to be reclaimed, the ClassLoader that loaded the class is also reclaimed, and the thread termination of the class is used.

3. In Java, different classloaders can load the same class, even if the class file is the same. However, the same ClassLoader cannot load a class repeatedly.

In general, hot replacement of classes in non-stop service is not a good idea, and the current version of Java simply does not allow developers to do so.

It is possible to create a new ClassLoader instance to change the content of the newly loaded Class, but the classes and objects loaded by the ClassLoader will not be modified, and it is very difficult to control when the Class can be recycled by the GC.

It’s better to just reboot.

However, we can still make a copycat version of hot replace by creating a new ClassLoader instance as mentioned earlier.

First, I prepared two target classes and compiled them into class files

The first:

package classloader;

public class Test {

    public void hello(a) {
        System.out.println("hello world");
// System.out.println("Are you OK");}}Copy the code

The second:

package classloader;

public class Test {

    public void hello(a) {
// System.out.println("hello world");
        System.out.println("Are you OK"); }}Copy the code

I’ll save the compiled class file for the second class separately and replace the first class in the future.

Then we have our own ClassLoader class:

package classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader2 extends ClassLoader {

    private String myClassPath;
    
    public MyClassLoader2(String path) {
        myClassPath = path;
    }

    publicClass<? > loadMyClass(String name){ System.out.println("Reload :"+name);
        
        File file = new File(myClassPath+File.separator+name.substring(0,name.indexOf(".")), name.substring(name.indexOf(".") +1,name.length())+".class");
        if(! file.exists()){return null;
        }
        
        try {
            
            FileInputStream is = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while((len = is.read()) ! = -1) { bos.write(len); }}catch (IOException e) {
                e.printStackTrace();
            }

            byte[] data = bos.toByteArray();
            is.close();
            bos.close();

            return defineClass(name, data, 0, data.length, null);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return null;
        
    }
    
    @Override
    publicClass<? > loadClass(String name)throws ClassNotFoundException {
        System.out.println("loadClass():"+name); Class<? > cls =null;
        if (cls == null){
            cls=loadMyClass(name);
        }
        if(cls==null){
            cls = getSystemClassLoader().loadClass(name); 
            System.out.println("getSystemClassLoader():"+ getSystemClassLoader());
        }
        if (cls == null) {throw new ClassNotFoundException(name);  
        }
        returncls; }}Copy the code

This custom loader rewrites the loadClass() method of the ClassLoader class. Note that classes under the target path are reloaded each time, with no judgment duplication.

The classLoader() method must have a class file in the specified directory before it can be loaded. Otherwise, the system-defined loader is used, because after overwriting the loaderClass() method, All related classes of the target class are also loaded using this method (such as the parent of the target class java.lang.object).

Finally, the test classes:

package classloader;

import java.lang.reflect.Method;

public class ClassLoaderTest {

    public static void main(String[] args) {
        
// loadClass();
        loadClass2();
        
    }
    
    public static void loadClass(a){
        
        try {
            // Initialize the loader
            MyClassLoader myLoader = new MyClassLoader("D:\\workspace\\test\\bin");

            / / load the class
            Class c = myLoader.loadClass("classloader.Test");

            / / verification
            Object obj = c.newInstance();
            Method method = c.getDeclaredMethod("hello".null);
            method.invoke(obj, null);
            
        } catch(Exception e) { e.printStackTrace(); }}public static void loadClass2(a){
        
        try {
            
            while(true) {// Initialize the loader
                MyClassLoader2 myLoader = new MyClassLoader2("D:\\workspace\\test\\bin");
                
                / / load the class
                Class c = myLoader.loadClass("classloader.Test");
                
                System.out.println(c.getClassLoader());
                System.out.println(Class.forName("classloader.Test").getClassLoader().toString());
                System.out.println();
                
                / / verification
                Object obj = c.newInstance();
                Method method = c.getDeclaredMethod("hello".null);
                method.invoke(obj, null);
                
                Thread.sleep(1000); }}catch(Exception e) { e.printStackTrace(); }}}Copy the code

The test class essentially creates a new instance of the ClassLoader every second and loads the target class with the new ClassLoader.

Before the program starts, the compile path is the Class file of the first target Class (Hello World). After the program starts, the second Class file (Are you OK) is replaced by the first one. The newly loaded target Class can call the methods of the second target Class.

The output is as follows:

LoadClass (): classloader.test Reloads: classLoader.Test

loadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

classloader.MyClassLoader2@616affac

sun.misc.Launcher$AppClassLoader@1ddd40f3

 

loadClass(a):java.lang.System Reload :java.lang.SystemgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

loadClass(a):java.io.PrintStream Reloads :java.io.PrintStreamgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

hello world

loadClass(a): classloader.test Reloads: classloader.testloadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

classloader.MyClassLoader2@170a6001

sun.misc.Launcher$AppClassLoader@1ddd40f3

 

loadClass(a):java.lang.System Reload :java.lang.SystemgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

loadClass(a):java.io.PrintStream Reloads :java.io.PrintStreamgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

Are you OK

loadClass(a): classloader.test Reloads: classloader.testloadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

classloader.MyClassLoader2@6ef82fe7

sun.misc.Launcher$AppClassLoader@1ddd40f3

 

loadClass(a):java.lang.System Reload :java.lang.SystemgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

loadClass(a):java.io.PrintStream Reloads :java.io.PrintStreamgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

Are you OK

loadClass(a): classloader.test Reloads: classloader.testloadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

classloader.MyClassLoader2@28a2f6b

sun.misc.Launcher$AppClassLoader@1ddd40f3

 

loadClass(a):java.lang.System Reload :java.lang.SystemgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

loadClass(a):java.io.PrintStream Reloads :java.io.PrintStreamgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

Are you OK

loadClass(a): classloader.test Reloads: classloader.testloadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@1ddd40f3

classloader.MyClassLoader2@6665e41

sun.misc.Launcher$AppClassLoader@1ddd40f3
Copy the code

As you can see from the output, the overwritten loadClass() method not only loads the target Test class, but also loads java.lang.Object, java.lang.system, etc.

Through the loadClass () method to get the Class, call Class. GetClassLoader () method to get the loader, is defined MyClassLoader2, each instance is different, The loader obtained by class.forname ().getClassLoader() is an AppClassLoader, and each instance is the same.

In addition, if only one instance of ClassLoader is used in the test class, an error will be reported if the target class is loaded multiple times in the loop, the code looks like this:

package classloader;

import java.lang.reflect.Method;

public class ClassLoaderTest {

    public static void main(String[] args) {
        
// loadClass();
        loadClass2();
        
    }
    
    public static void loadClass(a){
        
        try {
            // Initialize the loader
            MyClassLoader myLoader = new MyClassLoader("D:\\workspace\\test\\bin");

            / / load the class
            Class c = myLoader.loadClass("classloader.Test");

            / / verification
            Object obj = c.newInstance();
            Method method = c.getDeclaredMethod("hello".null);
            method.invoke(obj, null);
            
        } catch(Exception e) { e.printStackTrace(); }}public static void loadClass2(a){
        
        try {
            
            // Initialize the loader
            MyClassLoader2 myLoader = new MyClassLoader2("D:\\workspace\\test\\bin");
            
            while(true) {/ / load the class
                Class c = myLoader.loadClass("classloader.Test");
                
                System.out.println(c.getClassLoader());
                System.out.println(Class.forName("classloader.Test").getClassLoader().toString());
                System.out.println();
                
                / / verification
                Object obj = c.newInstance();
                Method method = c.getDeclaredMethod("hello".null);
                method.invoke(obj, null);
                
                Thread.sleep(1000); }}catch(Exception e) { e.printStackTrace(); }}}Copy the code

After the program starts, the output looks like this:

LoadClass (): classloader.test Reloads: classLoader.Test

loadClass(a):java.lang.Object Reload: java.lang.objectgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@28d320d6

classloader.MyClassLoader2@37b7a72b

sun.misc.Launcher$AppClassLoader@28d320d6

 

loadClass(a):java.lang.System Reload :java.lang.SystemgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@28d320d6

loadClass(a):java.io.PrintStream Reloads :java.io.PrintStreamgetSystemClassLoader(a):sun.misc.Launcher$AppClassLoader@28d320d6

Are you OK

loadClass(a)Reload :classloader.Test Exception in thread "main"java.lang.LinkageError:loader (instance of classloader/MyClassLoader2): attempted duplicate class definition for name: "classloader/Test"

         atjava.lang.ClassLoader.defineClass1(Native Method)

         atjava.lang.ClassLoader.defineClass(Unknown Source)

         atclassloader.MyClassLoader2.loadMyClass(MyClassLoader2.java:42)

         atclassloader.MyClassLoader2.loadClass(MyClassLoader2.java:58)

         atclassloader.ClassLoaderTest.loadClass2(ClassLoaderTest.java:43)

         atclassloader.ClassLoaderTest.main(ClassLoaderTest.java:10)
Copy the code

That is, the second load of the Test class returns an error.

Welcome to pay attention to the public number: Java treasure to receive more tutorial welfare