What is a classloader:
public class ClassInit { public static void main(String[] args) { ClassLoader c=ClassInit.class.getClassLoader(); } }
The ClassLoader above is the ClassLoader
Print c, and notice a Launcher class:
sun.misc.Launcher$AppClassLoader@18b4aac2
Enter the Launcher class and notice two pieces of code:
var1 = Launcher.ExtClassLoader.getExtClassLoader(); this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
What is the relationship between ExtClassLoader and AppClassLoader?
Modify to the following code:
public class ClassInit { public static void main(String[] args) { ClassLoader c = ClassInit.class.getClassLoader(); while (c != null) { System.out.println(c); c = c.getParent(); } } }
Print:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1540e19d
So we come to the conclusion: AppClassLoader has a father who is ExtClassLoader
Continue to analyze ClassLoader, and notice a piece of code:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> 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)
Exclusive lock ensures that only one class can be loaded at the same time
Then check whether the class has been loaded and return directly if it has been loaded;
If it has not been loaded, it will load its father recursively until there is no father, and finally execute findBootstrapClassOrNull()
Looking down, I find this Code:
// return null if not found private native Class<?> findBootstrapClass(String name);
This function has no function body and is modified by native, which means calling a local method
The local method is called here, and the local method interface is different according to the operating system, and then the local method library is called.
come to conclusion:
The loading order of a class is: bootstrappclassloader --- > extclassloader --- > appclassloader
The checking order of a class is: appclassloader --- > extclassloader --- > bootstrappclassloader
Why does the loading order start with bootstrappclassloader?
Write a new code. The package name and class name are the same as the java source List:
package java.util; public class List{ public static void main(String[] args){ xxxxxx } }
Discovery failed to run, error reported: main method not found in class java.util.List
It's very reasonable that it can't run, otherwise a hacker can easily embed virus code, and then add it to the JVM through a custom classloader
This mechanism is called: parental appointment
Purpose: Safety
1. If the parent class can be loaded, the child class is not allowed to load
2. Ensure that a class is loaded only once
To judge whether two objects are equal, the most important condition is to see whether they are a classloader:
Write a code:
package org.dreamtech.cl; import java.io.IOException; import java.io.InputStream; public class ClassInit { //Custom class loader public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ClassLoader loader = new ClassLoader() { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { try { String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream is = getClass().getResourceAsStream(fileName); if (is == null) { return super.loadClass(name); } byte[] b = new byte[is.available()]; is.read(b); return defineClass(name, b, 0, b.length); } catch (IOException e) { throw new ClassNotFoundException(); } } }; String className = "org.dreamtech.cl.ClassInit"; Object o1 = ClassInit.class.getClassLoader().loadClass(className).newInstance(); Object o2 = loader.loadClass(className).newInstance(); System.out.println(o1 == o2); System.out.println(o1.equals(o2)); System.out.println(o1 instanceof org.dreamtech.cl.ClassInit); System.out.println(o2 instanceof org.dreamtech.cl.ClassInit); System.out.println(o1.getClass().getClassLoader()); System.out.println(o2.getClass().getClassLoader()); } }
Print as follows:
false false true false sun.misc.Launcher$AppClassLoader@18b4aac2 org.dreamtech.cl.ClassInit$1@14ae5a5