preface

  • To learn, you should read the official JavaDoc, JavaDoc is the first hand information, should be accurate.
  • This section is focused on translating the document comments in the ClassLoader class. If there is any problem, please read the English comments.

The English version

translation

  • Class loaders areThe object responsible for loading the class. ClassLoader is an abstract class. The binary name of a given class (binary name), the classloader should tryTo locate or generate.(locate or generateThe data that makes up the class definition. The typical strategy is to convert the name to a file name and then read the “class file” of that name from the file system.

Remark:

  • Given the name of the class, the classloader finds the data that defines the corresponding class.
  • binary name:It’s just a string
    • “java.lang.String”
    • “javax.swing.JSpinner$DefaultEditor”( $Followed by the class name of the inner class)
    • “java.security.KeyStore$Builder$FileBuilder$1 “(The $1The first anonymous inner class in the
    • “java.net.URLClassLoader$3$1″(the first anonymous inner class in URLClassLoader’s third anonymous inner class)
  • To locate or generate.(locate or generate) :positioningBecause the class exists somewhere on the disk waiting to be loaded, saidgenerateBecause some classes are generated dynamically, such as dynamic proxies.
  • Each Class object contains a reference to the ClassLoader that defines it.

Note: There is a member variable ClassLoader in Class Class, so Class Class has a getClassLoader() method.

  • The class objects of the array class are not created by the class loader, but are created automatically according to the requirements of the Java runtime. Class.getclassloader () returns an array Class with the same classloader as its element type; If the element type is primitive, the array class has no classloader.

    • The sample description
    public class ClassLoaderTest3 {
      public static void main(String[] args) {
          String[] strings = new String[2];
          System.out.println(strings.getClass().getClassLoader());// The element type is String and is loaded with BootStrap
          System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
          ClassLoaderTest3[] classLoaderTest3s = new ClassLoaderTest3[2];
          System.out.println(classLoaderTest3s.getClass().getClassLoader());
          System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
          int[] a = new int[2]; System.out.println(a.getClass().getClassLoader()); }}Copy the code
    • The results of

  • The application implements (inherits) a ClassLoader to extend the way the Java Virtual Machine loads classes dynamically.

Note: The purpose of the custom ClassLoader is to extend the way the Java Virtual Machine loads classes dynamically. By default, classes are loaded by parent delegation. If you don’t like the parent delegation mechanism, you can inherit the ClassLoader to implement different loading methods.

  • The security manager can usually use class loaders to indicate security domains.

Comments: I don’t understand, baidu.

  • The ClassLoader class uses the delegate model to search for classes and resources. Each instance of a ClassLoader has an associated parent ClassLoader. When requested to find a class or resource, a ClassLoader instance delegates the search for the class or resource to its parent ClassLoader and then attempts to find the class or resource itself. The built-in ClassLoader of a VM is called a “Bootstrap ClassLoader”. It does not have a parent, but can act as the parent of a ClassLoader instance.
  • Support concurrent load class class loader was known as the class loader with parallel ability, and the need to the class initialization time by calling this the registerAsParallelCapable method to register themselves, make its can parallel loading classes. Note that the ClassLoader class is registered with parallelism capability by default. However, while they have parallelism capabilities, their subclasses still need to register themselves.
  • In environments where the delegate model is not strictly hierarchical, class loaders need to be capable of parallelism, or class loading will result in deadlocks because the loader lock is held throughout the class loading process (see the loadClass method).
  • Typically, the Java Virtual Machine loads classes from the local file system in a platform-dependent manner. For example, on UNIX systems, the virtual machine loads classes from a directory defined by the CLASSPATH environment variable.
  • However, some classes may not come from files; They can come from other sources, such as the network, or they can be built by an application. The defineClass method converts a byte array to an instance of Class. You can use class.newinstance to create an instance of this newly defined Class.
  • The classloader creates objects that reference other classes in their methods and constructors. To determine the referenced class, the Java virtual Machine calls the loadClass method of the classloader that originally created the class.

Method (){return new String(“hehe”); }, which references the String class.

Let’s add some code to that

Custom class loaders

  • Before I start, the above document says:
    • DefineClass converts a byte array to an instance of Class Class. You can use class.newinstance to create an instance of this newly defined Class.
    • DefineClass parameters

    • Again, the classloader needs to find the class to load before it can load, as mentioned abovebinary nameIs the key.
  • There are some problems with this custom code, so let’s take a look
public class UserClassLoader extends ClassLoader {
    private String classLoaderName;
    private final String SUFFIX = ".class";
    private String path;
    
    public void setPath(String path) {
       this.path = path;
    }

    public UserClassLoader(String classLoaderName) {// The constructor
        super(a);// The system class loader is the parent of the loader
        this.classLoaderName = classLoaderName;
    }
    // Constructor. You can specify the constructor of the superclass loader
    public UserClassLoader(ClassLoader parent, String classLoaderName) {
        super(parent);// Explicitly define the parent of the class loader
        this.classLoaderName = classLoaderName;
    }

    @Override
    public String toString(a) {
        return "classLoaderName='" + classLoaderName;
    }

    @Override
    protectedClass<? > findClass(String className) {/ / rewrite
        byte[] data = loaderClassData(className);
        return defineClass(className,data,0,data.length);// The byte array becomes a Class
    }
    private byte[] loaderClassData(String className) {// Turn the class file into a byte array
        InputStream in = null;
        ByteArrayOutputStream outputStream = null;
        byte[] data = null;
        try {
            className = className.replace("."."/");
            in = new FileInputStream(path + className + SUFFIX);// File input stream
            outputStream = new ByteArrayOutputStream();// Byte output stream
            int ch;
            while((ch = in.read()) ! = -1) {
                outputStream.write(ch);
            }
            data = outputStream.toByteArray();// Byte array
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Optional.ofNullable(in).ifPresent(i -> {
                try {
                    i.close();/ / close the flow
                } catch(IOException e) { e.printStackTrace(); }}); Optional.ofNullable(outputStream).ifPresent(i -> {try {
                    i.close();/ / close the flow
                } catch(IOException e) { e.printStackTrace(); }}); }return data;// Return a byte array. The contents of an array are classes
    }

    public static void main(String[] args) throws Exception {
        UserClassLoader userClassLoader = new UserClassLoader("userClassLoader");
        UserClassLoader.test(userClassLoader);
    }
    public static void test(ClassLoader classLoader) throws Exception {/ / test
       // Specify the class file to load. It cannot be the current class. The class name is binary nameClass<? > clazz = classLoader.loadClass("com.jvmstudy.classloading.ClassLoaderTest");
        Object object = clazz.newInstance();// Generate an instance of the class
        System.out.println(object);/ / print}}Copy the code
  • The result, of course, is the class name

So the question is, are the custom class loaders used

  • In the code above, add the following print statement to the findClass method
    @Override
    protectedClass<? > findClass(String className) { System.out.println("findClass invoke: "+className);
        System.out.println("classLoader name: "+classLoaderName);
        byte[] data = loaderClassData(className);
        return defineClass(className,data,0,data.length);
    }
    Copy the code
  • As a result, the class is loaded without using a custom class loader.

  • Print out in the test method which loader the class was loaded by
        public static void test(ClassLoader classLoader) throws Exception {
          // Load the class, not the current classClass<? > clazz = classLoader.loadClass("com.jvmstudy.classloading.ClassLoaderTest");
           Object object = clazz.newInstance();
           System.out.println(object);
           System.out.println(object.getClass().getClassLoader());
    Copy the code
  • As a result, the class is loaded by the system (App) classloader

Why is there a situation where the custom classloader is not being used

  • You can see that the first constructor is used when instantiating the custom classloader in the main method.
    public UserClassLoader(String classLoaderName) {// The constructor
        super(a);// The system class loader is the parent of the loader
        this.classLoaderName = classLoaderName;
    }
    Copy the code
  • According to the parent delegation mechanism, when a class is loaded using a custom classloader, it delegates the loading to its parent (AppClassLoader, or system classloader). So, finally is the system class loader to load “com. Jvmstudy. Classloading. ClassLoaderTest”

further

  • The system class loader is the default output path of the.class file compiled by the.java file

  • Delete the class file loaded in the default path.

  • The main method is as follows:
    public static void main(String[] args) throws Exception {
          UserClassLoader userClassLoader = new UserClassLoader("userClassLoader");
          userClassLoader.setPath("C:/Users/25852/Desktop/");
          // Cannot be the current classClass<? > clazz = userClassLoader.loadClass("com.jvmstudy.classloading.ClassLoaderTest");
          Object object = clazz.newInstance();
          System.out.println("class HashCode: "+clazz.hashCode());
          System.out.println(object.getClass().getClassLoader());
      } 
    
    Copy the code
  • Results:

  • What is the reason why?
    • Again, the custom class loader will not load the class itself first due to parent delegation. However, the parent class loader will not be able to load the class first, not to mention the root class loader and the extended class loader, and the system class loader will not be able to load the class because the class file in the default path has been deleted.
    • Finally, once it’s all delegated, the custom class has to load itself. We’ve told the custom class to load the class on the desktop.

Recompile to regenerate the class file that was originally deleted

  • The main method is adapted as follows:
    public static void main(String[] args) throws Exception {
          UserClassLoader userClassLoader = new UserClassLoader("userClassLoader"); Class<? > clazz = userClassLoader.loadClass("com.jvmstudy.classloading.ClassLoaderTest");// Cannot be the current class
          Object object = clazz.newInstance();
          System.out.println("class HashCode: "+clazz.hashCode());
          System.out.println(object.getClass().getClassLoader());
          System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
          UserClassLoader userClassLoader2 = new UserClassLoader("userClassLoader2"); Class<? > clazz1 = userClassLoader2.loadClass("com.jvmstudy.classloading.ClassLoaderTest");// Cannot be the current class
          Object object1 = clazz1.newInstance();
          System.out.println("class HashCode: "+clazz.hashCode());
          System.out.println(object1.getClass().getClassLoader());
      }
    Copy the code
  • Results:

  • Note A class can be loaded only once.

As usual, delete the class from the default path and move it to the desktop

  • The main method is adapted as follows:
    public static void main(String[] args) throws Exception {
          UserClassLoader userClassLoader = new UserClassLoader("userClassLoader");
          userClassLoader.setPath("C:/Users/25852/Desktop/"); Class<? > clazz = userClassLoader.loadClass("com.jvmstudy.classloading.ClassLoaderTest");// Cannot be the current class
          Object object = clazz.newInstance();
          System.out.println("class HashCode: "+clazz.hashCode());
          System.out.println(object.getClass().getClassLoader());
          System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
          UserClassLoader userClassLoader1 = new UserClassLoader("userClassLoader1");
          userClassLoader1.setPath("C:/Users/25852/Desktop/"); Class<? > clazz1 = userClassLoader1.loadClass("com.jvmstudy.classloading.ClassLoaderTest");// Cannot be the current class
          Object object1 = clazz1.newInstance();
          System.out.println("class HashCode: "+clazz1.hashCode());
          System.out.println(object1.getClass().getClassLoader());
      }
    Copy the code
  • Results:

  • The same class is only loaded once. Why is that wrong?
    • This is where the class loader namespace comes in.
    • Namespaces will be covered in the next 100 million blogs.