First, summarize the knowledge:
1. Each class loader has its own namespace, which consists of the loader and all classes loaded by the parent loader.
2. In the same namespace, two classes with the same complete name (including the package name of the class) will not appear.
3. In different namespaces, there may be two classes with the same complete name (including the package name of the class).
4. The class loaded by the child loader can load the class loaded by the parent loader.
5. The class loaded by the parent loader cannot load the class loaded by the child loader lock.
We will explain the above in detail later. Please continue to follow the blog.
For example, there are four classes:
JavaTest1.java: the main class used to call the loader to load.
JVMTest1.java: custom class loader.
People.java: the class contains only one parameterless constructor, in which an object of Man class is created.
Man.java: contains only one parameterless constructor.
Next, paste the code in turn:
JavaTest1.java
public class JavaTest1 { public static void main(String[] args) throws Exception { /*loader1 loader*/ JVMTest1 loader1 = new JVMTest1("loader1"); loader1.setPath("C:\\Users\\admin\\Desktop\\"); Class<?> clazz1 = loader1.loadClass("People"); System.out.println("clazz1 Loader:"+clazz1.getClassLoader()); Object object = clazz1.newInstance();//Experiment two } }
Jvmtest1.java (for those who do not understand the code, please refer to my last blog).
import java.io.*; public class JVMTest1 extends ClassLoader{ private String classLoaderName; private final String fileExtension = ".class"; private String path; public void setPath(String path) { this.path = path; } public JVMTest1(String classLoaderName){ super(); this.classLoaderName = classLoaderName; } public JVMTest1(ClassLoader parent, String classLoaderName){ super(parent); this.classLoaderName = classLoaderName; } @Override protected Class<?> findClass(String className){ byte[] data = this.loadClassData(className); System.out.println("Run a custom classloader"+this.classLoaderName); return this.defineClass(className,data,0, data.length); } private byte[] loadClassData(String className) { FileInputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; try { className = className.replace(".","\\"); is = new FileInputStream(new File(this.path+className+ this.fileExtension)); baos = new ByteArrayOutputStream(); int ch = 0; while((ch = is.read())!=-1){ baos.write(ch); } data = baos.toByteArray(); } catch (Exception ex){ ex.printStackTrace(); }finally { try{ is.close(); baos.close(); }catch (Exception ex){ ex.printStackTrace(); } } return data; } }
People.java
public class People { public People(){ System.out.println("People Of ClassLoader Yes,"+ this.getClass().getClassLoader()); new Man(); //The following sentence is the annotation of Experiment 6 //System.out.println("print man. Class in People:" + man. Class); } }
Man.java
public class Man { public Man(){ System.out.println("Man Of ClassLoader Yes,"+ this.getClass().getClassLoader()); //The following sentence is the annotation of Experiment 7 // System.out.println("print people. Class in Man:" + people. Class); } }
Experiment 1:
1. Run the above codes normally and observe the operation results.
2. Because the People class can be loaded by the system class loader, and the Man class is created in the People class, which is an active use of the Man class, so it needs to be loaded and then loaded by the system class. Isn't that a big problem?
Experiment two:
3. Comment out the line "Experiment 2" in JavaTest1, and observe the running results.
4. Why is the output written in People.java and Man.java not running? Let's see, where are our output statements written? It's written in the constructor. In JavaTest, we only let it load but not run, so we need to create an instance of the People class before it will run.
Experiment three:
5. Move these two classes to the desktop (the purpose of this is to make the system class loader unable to load, so that our custom loader can work). Observe the operation results.
6. The people class and Man class are successfully loaded by our custom loader.
Experiment four:
7. Move People.class to the desktop and observe the results
8. When People.class is loaded, the system class loader cannot find where, so it can only be loaded by the user-defined loader.
When Man.class is loaded, the system class loader can find it, so Man is loaded by AppCLassLoader.
Experiment five:
9. Also move Man.class to the desktop and observe the running results.
10. See that the People class is successfully loaded by the system class, but the Man class cannot be found. Some students may wonder that the Man.class system class loader cannot be loaded. The user-defined class loader should be able to load! Let's take a closer look at our custom loaded code
This is to indicate the storage address of People.class on the desktop. There is no Man, so the program will report an error.
Experiment six:
11. Move People.java to the desktop, remove the comments in People.java, and observe the running results.
12. You can see that People are loaded by custom class loader, Man is loaded by system class, and People can use the class loaded by system class.
Experiment seven:
13. Move People.java to the desktop, remove the comments in Man.java, and observe the running results.
14. Direct error reporting. This is because the class loaded in the child loader can load the class loaded in the parent loader, and the class loaded in the parent loader cannot load the class loaded in the child loader lock. They have an inclusive relationship as follows:
If you don't understand, please leave a message to discuss.