Class loaders

After understanding the whole process of class loading and initialization, it is necessary to talk about the concept of class loader, because the above process must be implemented by the loader.

Class loaders, while only used to implement the loading action of a class, play a much bigger role in a Java program than the class loading phase. For any class, its uniqueness in the Java Virtual Machine must be established by the class loader that loads it and the class itself, each of which has a separate class namespace. This sentence can express more popular: compare whether the two classes “equal”, only in these two classes are from the same Class loader under the premise of load to be meaningful, otherwise, even if these two classes derived from the same Class files, by the same Java virtual machine loading, as long as the load they’re different Class loaders, these two classes are not necessarily equal.

We can use the instanceof keyword to determine object ownership, such as the following code:

public class ClassLoaderTest {
    public static void main(String[] args) throws Exception {
        ClassLoader myLoader = new ClassLoader() {
            @Override
            publicClass<? > loadClass(String name)throws ClassNotFoundException {
                try {
                    / / get a class name of the class, such as com. Coder404. Demo4. ClassLoaderTest, intercepting splicing called ClassLoaderTest. After the class
                    String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    // Get the byte stream
                    InputStream is = getClass().getResourceAsStream(fileName);
                    if (is == null) {
                        // If the file is not found, pass it to the parent loader for loading
                        return super.loadClass(name);
                    }
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    // Convert the byte array to an instance of Class. Before a class can be used, it must be resolved.
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    throw newClassNotFoundException(name); }}}; Object obj = myLoader.loadClass("com.coder404.demo4.ClassLoaderTest").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceofcom.coder404.demo4.ClassLoaderTest); }}Copy the code

Running result:

class com.coder404.demo4.ClassLoaderTest
false
Copy the code

Code above us by creating a custom class loader for the a called “com. Coder404. Demo4. ClassLoaderTest” classes, and instantiate the object.

In two lines of the output, we can see that the first line can see this is indeed the com object. Coder404. Demo4. ClassLoaderTest instantiation, but in the second line in the output only to find the object types and classes do belong to check when back to false. This is because there are two ClassLoaderTest classes in the Java Virtual Machine. One is loaded by the vm’s application Class loader, and the other is loaded by our custom Class loader. Although they are both from the same Class file, they are still separate classes in the Java Virtual Machine. The result of checking the type of the object is false.

Java class loaders are divided into the following types:

The name of the Which class to load instructions
Bootstrap ClassLoader JAVA_HOME/jre/lib No direct access
Extension ClassLoader JAVA_HOME/jre/lib/ext The superior is Bootstrap, and null is displayed
Application ClassLoader classpath The superior for the Extension
Custom class loaders The custom The superior for the Application
(1) Start the class loader

The Bootstrap ClassLoader is mainly responsible for loading core class files in the Java directory installed on the machine, namely, the lib directory under the JRE directory in the JDK installation directory. The Bootstrap ClassLoader stores some core class libraries required for running Java.

When the JVM starts, it first loads the core class libraries in our lib directory using the startup class loader.

(2) Extend the classloader

Extension ClassLoader is used to load files from ext in the lib directory of the JRE. This class is used to support the running of our system.

(3) Application class loaders

Application ClassLoader Loads classes in the path specified by the “classpath” environment variable, which can be understood as loading our own Java code

(4) Custom class loaders

In addition to the above three types, you can also customize the class loader, according to the specific needs to load the corresponding class.

Iii. Parent delegation mechanism

A parent delegate is a call to the loadClass method of the classloader that looks up the rules of the class

Pay attention to

In this case, the parents, which would be better translated as the superiors, are not inherited

The structure diagram is as follows:

Based on this parent-child hierarchy, there is a parent delegate mechanism: get the “father” to load the class first, and if not, get the son to load the class again, so that the multi-level loader structure can avoid repeatedly loading certain classes.

The core method loadClass in class loader source code:

protectedClass<? > loadClass(String name,boolean resolve)
        throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        // 1. Check whether the class is loadedClass<? > c = findLoadedClass(name);if (c == null) {
            long t0 = System.nanoTime();
            try {                
                if(parent ! =null) {
                    // 2. Assign a loadClass to a parent
                    c = parent.loadClass(name, false);
                } else {
                    // 3. If there is no more (ExtClassLoader), delegate BootstrapClassLoaderc = findBootstrapClassOrNull(name); }}catch (ClassNotFoundException e) {
            }
           
            if (c == null) {
                long t1 = System.nanoTime();
                // 4. If each layer is not found, call the findClass method (which each classloader extends itself) to load it
                c = findClass(name);

                // 5. Record the timesun.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

Test code:

public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException { Class<? > aClass = Demo4.class.getClassLoader() .loadClass("com.coder404.demo4.ToLoaded"); System.out.println(aClass.getClassLoader()); }}Copy the code

The execution process is:

  1. sun.misc.Launcher$AppClassLoader//1, start to look at the loaded classes, the result is not
  2. sun.misc.Launcher$AppClassLoader// 2, delegate superiorsun.misc.Launcher$ExtClassLoader.loadClass()
  3. sun.misc.Launcher$ExtClassLoader// 1, look at the loaded class, the result is not
  4. sun.misc.Launcher$ExtClassLoader// 3, there is no superior, then delegateBootstrapClassLoaderTo find the
  5. BootstrapClassLoaderJAVA_HOME/jre/lib to find ToLoaded this class
  6. sun.misc.Launcher$ExtClassLoaderJAVA_HOME/jre/lib/ext/ToLoaded classsun.misc.Launcher$AppClassLoaderAt / / 2
  7. Proceed tosun.misc.Launcher$AppClassLoader// 4, it calls its own findClass method, looks under the classpath, and finds it