1. Class Loader Introduction
The class loader is responsible for loading the class file into memory and generating the corresponding Java.lang.Class object for it. For any class, it is necessary to load its class loader and the class itself to determine the uniqueness of the class in the JVM, that is to say, The same class file loads and creates two Java.lang.Class objects with two different classloader, even if two objects originate from the same class file, they are also unequal, where "equal" includes the Equals () method of the Class object, IsAssignableFrom () method, Isinstance () method, also includes using the INSTANCEOF keyword to determine the relationship of the object.
The verification code is as follows:
public class Classloadertest {public static void main (string[] args) throws ClassNotFoundException, Illegalaccessexcep tion, instantiationexception {//Custom class loader ClassLoader Myloader = new ClassLoader () {@Override Public class<?> loadclass (string name) throws ClassNotFoundException {string fileName = Nam E.substring (Name.lastindexof (".") + 1) + ". Class"; InputStream is = GetClass (). getResourceAsStream (FileName); if (is = = null) {return super.loadclass (name); } try {byte[] buff = new byte[is.available ()]; Is.read (Buff); Return defineclass (name, buff, 0, buff.length); } catch (IOException e) {throw new classnotfoundexception (name); } } }; Load Classloadertest.classloadertest Class Clazz = MYLOADER.LOADC using a custom class loadLass ("Classloadertest.classloadertest"); Object obj = clazz.newinstance (); /* The class instance that created the Obj object is loaded by the custom class loader, and the ClassLoader used by Classloadertest.classloadertest is the system ClassLoader, and the owning relationship is inconsistent */syste M.out.println (obj instanceof classloadertest.classloadertest); /* The Clazz class instance is loaded by a custom ClassLoader, and the ClassLoader used by ClassLoaderTest.ClassLoaderTest.class is the System class loader/System.out. println (Clazz.getclassloader ()); System.out.println (ClassLoaderTest.ClassLoaderTest.class.getClassLoader ()); System.out.println (Clazz.equals (ClassLoaderTest.ClassLoaderTest.class)); }}
Output Result:
False[email Protected]sun.misc.launcher[email Protected]false
2. Class Loader classification
From the point of view of a Java virtual machine, there are only two different classloader: one is to start the ClassLoader (Bootstrap ClassLoader), which is part of the virtual machine, and all the other ClassLoader, all of which are implemented by the Java language. Independent of the virtual machine, and all inherit from Java.lang.ClassLoader. In terms of subdivision, the ClassLoader can also be divided into the following categories:
- Bootstrap ClassLoader: Root class Loader
- Extension ClassLoader: Extension class Loader
- System ClassLoader: Application class Loader
- User-defined class loader
2.1 Bootstrap ClassLoader
Bootstrap ClassLoader is called the root classloader, and it is responsible for loading the core classes of Java. The root ClassLoader is not a subclass of Java.lang.ClassLoader, but is implemented by the JVM itself. In Sun's JVM, when executing the java.exe command, use-xbootclasspath to select or specify the Sun.boot.class.path system property value using the-D option to specify that additional classes should be loaded.
View the path of the class loaded by the root ClassLoader by the following program:
public class Loadertest {public static void Main (string[] args) throws IOException { //gets all the URL array loaded by the root ClassLoader U rl[] urls = Launcher.getbootstrapclasspath (). Geturls (); Traverse, output all URLs loaded by the root ClassLoader System.out.println ("All url************* loaded by the ********* root loader"); for (URL url:urls) { System.out.println (Url.toexternalform ());}}}
Output Result:
All url*************file:/d:/java/jdk1.7.0_80/jre/lib/resources.jarfile:/d:/java/jdk1.7.0_80/loaded by the root ClassLoader jre/lib/rt.jarfile:/d:/java/jdk1.7.0_80/jre/lib/sunrsasign.jarfile:/d:/java/jdk1.7.0_80/jre/lib/jsse.jarfile:/ D:/java/jdk1.7.0_80/jre/lib/jce.jarfile:/d:/java/jdk1.7.0_80/jre/lib/charsets.jarfile:/d:/java/jdk1.7.0_80/jre /lib/jfr.jarfile:/d:/java/jdk1.7.0_80/jre/classes
2.2 Extension ClassLoader
Extension ClassLoader is an extension class loader that is responsible for loading the class of the jar package in the JRE's extended directory, or all class libraries in the path specified by the Java.ext.dirs system variable, and developers can use the extension class loader directly.
2.3 Application ClassLoader
The application ClassLoader is an application class loader, implemented by Sun.misc.launcher$appclassloader, and can be obtained by the Classloader.getsystemclassloader () method , so it is also known as the system ClassLoader. It is responsible for loading the class library specified on the user classpath (ClassPath), which the developer can use directly, and if the application does not have a custom classloader, this is typically the default ClassLoader in the program.
2.4 Custom class Loader
To implement the personalization of class loading, we can implement a custom class loader by extending the Java.lang.ClassLoader class, and the detailed implementation is described later.
Our applications are typically loaded by these kinds of loaders, and the relationship between the ClassLoader
The relationship between class loaders is not a parent-child relationship of class-inherited nature, but a composite relationship.
3. Steps for class loader load class
When the ClassLoader loads a class, it delegates the loaded request to the parent loader, and if the parent loader still has a parent (only the root loader does not have a parent loader), it is delegated to its parent loader again, and all the load requests are passed to the root ClassLoader. The class is loaded only when the class of the delegate cannot be loaded in the parent class loader. The obvious benefit of this way of loading is that in a running JVM, all classes are not loaded by different classloader, and a class sees the same class object in each loader environment.
In addition, when a class loader is responsible for loading a class, the other classes referenced by that class are also loaded by the ClassLoader, unless explicitly loaded with another class loader.
The class loading of the JVM has a caching mechanism, and if a class has already been loaded, then when the class is used again in the program, the class is fetched directly from the cache, and the class loader will read the class's binary data and create the class object for that type only if the class is not present in the cache. This also provides a good explanation of why the JVM changes need to be restarted to take effect after the Java code has been modified. However, there is now a technology that can be used to modify Java code without restarting the JVM to remain in effect.
4. Creating a custom class Loader
In the process of routine development, we may want to customize some classloader for some reason. It is generally recommended to extend the ClassLoader class and override the Findclass method to implement a custom class loader.
Next we customize the implementation of a load class that can directly load the source code, the implementation of the principle is very simple, the source of the compilation in the class loader execution:
Import Java.io.file;import java.io.fileinputstream;import java.io.ioexception;import java.lang.reflect.Method;/** * Author:xszhaobo * <p/> * DATE:2016/5/7 * <p/> * package_name:JVMTest.myclassloader * <p/> * Project: _da Rksiderg */public class Compileclassloader extends ClassLoader {public static void main (string[] args) throws Exceptio n {if (Args.length < 1) {System.out.println ("Missing target class:"); System.out.println ("Java compileclassloader ClassName"); }//The first parameter specifies the class name that needs to be run String Progclass = args[0]; Some other parameters string[] Progargs = new String[args.length-1]; System.arraycopy (args,1,progargs,0,progargs.length); Specifies the class loader Compileclassloader loader = new Compileclassloader (); Class clazz = Loader.loadclass (Progclass); Main refers to the method name//new string[0]). GetClass () indicates that the formal parameter type of main corresponds to class Method main = Clazz.getmethod ("Main", (New Strin G[0]). GetClass ()); Object[] Argsarray = {Progargs}; The first parameter represents the object to which the method needs to be called, and if a static method is called, it can be set to NULL//second and later to indicate the parameter passed in by the method Main.invoke (Null,argsarray); } @Override protected class<?> findclass (String name) throws ClassNotFoundException {System.out.printl N ("Load class:" + Name + ". Java"); Class clazz = null; String filestub = name.replaceall ("\ \", "/"); String javafilename = Filestub + ". Java"; String classfilename = Filestub + ". Class"; File Javafile = new file (javafilename); File Classfile = new file (classfilename); The Java source file exists and the class file does not exist, or the Java source file is modified later than the class file if (Javafile.exists () && (!classfile.exists () || Javafile.lastmodified () > Classfile.lastmodified ()) {try {if (!compile (javafilename) | |!c Lassfile.exists ()) {throw new ClassNotFoundException ("ClassNotFoundException:" + javafilename); }} catch (IOException e) { E.printstacktrace (); } if (Classfile.exists ()) {try {byte[] raw = GetBytes (Classfilename); Clazz = This.defineclass (name,raw,0,raw.length); } catch (IOException e) {e.printstacktrace (); }}} if (clazz = = null) {throw new classnotfoundexception (name); } return clazz; } private Boolean compile (String javafile) throws IOException {System.out.println ("Compileclassloader compile" + Java File + "..."); Process p = runtime.getruntime (). EXEC ("javac-encoding utf-8" + javafile); try {p.waitfor (); } catch (Interruptedexception e) {e.printstacktrace (); } int ret = P.exitvalue (); return ret = = 0; } private byte[] getBytes (String filename) throws IOException {File File = new file (fileName); Long length = File.length(); byte[] bytes = new byte[(int) length]; Using Java 7 features: Try statement with Resource management try (FileInputStream FIS = new FileInputStream (file)) {int Readlen = Fis.re Ad (bytes); if (readlen! = length) {throw new IOException ("The entire contents of the unreadable file:" + fileName); } return bytes; }//versions prior to Java 7 Use this resource management method/*try {int readlen = fis.read (bytes); if (readlen! = length) {throw new IOException ("The entire contents of the unreadable file:" + fileName); } return bytes; } finally {fis.close (); }*/ }}
Compile the class:
Javac-encoding Utf-8-xlint:unchecked Compileclassloader.java
Meaning of the instruction
Javac is a compile command;
-encoding Utf-8 The specified encoding is utf-8;
-xlint:unchecked refers to the need to specify-xlint:unchecked compilation because Compileclassloader.java uses an unchecked or unsafe operation;
Compileclassloader.java refers to files that need to be compiled.
Under the same folder, write a test main class casually:
/** * Author:xszhaobo * <p/> * DATE:2016/5/9 * <p/> * package_name:JVMTest.myclassloader * <p/> * PROJEC T: _darksiderg */public class Hellotest {public static void Main (string[] args) { System.out.println ("parameter:" + arg S[0]);} }
At this point, use Compileclassloader as the class loader at the command line to run the source code directly with the Java command:
Java Compileclassloader hellotest This is a parameter
Output results at first load:
Compileclassloader Compiling Hellotest.java ... Parameter: This is a parameter
You can see that this is the first time that you have compiled the Hellotest.java file and then run the main method in that class.
But here's a question, if you modify the Hellotest.java source code at this point, re-execute the following command:
Java Compileclassloader hellotest This is a parameter
Results of the output:
Parameter: This is a parameter
The output at this time does not contain the phrase "Compileclassloader compiled Hellotest.java ...", stating that this time the source code has not been recompiled, the cause of the problem has not been found, and if you know the answer, you might as well tell me.
There are also areas to note:
1. The directory where the command is executed should be the directory where the Java source file resides;
2. Definition of class in source code do not specify a package, and if you specify a package, you need to do further processing when compiling the source code and specifying the loader.
Java Class Loader Introduction