Objective
Java reflection, the most commonly used Class.forName () method. At completion, the code string is received and the code string is generated by Javacompiler (stored in the bin directory in the Eclipse Project, under Classpath), and then through the Java reflection mechanism, the main method is obtained and executed. The class file name is fixed. When the A.class file is updated, the problem occurs, and the result of the execution of the main method is the same as the result of the first execution.
Program Flow
Code submission, receive code, compile to A.class file->java reflection->main Method execution
Specific code reference: http://www.cnblogs.com/hujunzheng/p/5203067.html
Cause of the problem
The delegate mechanism of the class loader! Speaking of which, we have to introduce the Java ClassLoader.
Class loaders in Java virtual machines
multiple ClassLoader can be installed in a Java virtual machine, and the system defaults to three main class loaders, each of which is responsible for loading classes at a particular location: BootStrap,extclassloader,appclassloader
The ClassLoader is also a Java class, because the class loader of the Java class is also loaded by the ClassLoader itself, and it is clear that the first ClassLoader is not a Java class, which is BootStrap, written in C + + code, has been encapsulated in the JVM kernel, and Extclassloader and Appclassloader are Java classes.
Property structure diagram for class loader
A picture of theft:
This leads to the conclusion
First my A.class file was updated, then the call to Class.forName () [I want to reload the bytecode file object], then finally loaded by Appclassloader, one of the functions is very important, that is loadclass (), Take a look at the source code for this function, as follows:
protectedClass<?> loadclass (String name,BooleanResolvethrowsclassnotfoundexception{//plus lock, synchronous processing, because it may be multithreaded in the load class synchronized(Getclassloadinglock (name)) {//Check to see if the class has already been loaded, and if it has been loaded, it will not load theClass C =Findloadedclass (name); if(c = =NULL) { LongT0 =System.nanotime (); Try { //if the parent of the custom class loader is not NULL, the loadclass of the parent is called to load the class if(Parent! =NULL) {C= Parent.loadclass (Name,false); } Else { //if the parent of the custom ClassLoader is null, call the Findbootstrapclass method to find the class, which is the Bootstrap class loaderc =findbootstrapclassornull (name); } } Catch(ClassNotFoundException e) {//ClassNotFoundException thrown if class not found//From the Non-null parent class loader } if(c = =NULL) { //If still not found, then invoke Findclass in order//To find the class. LongT1 =System.nanotime (); //if the parent load class fails, it calls its own Findclass method for class loadingc =Findclass (name); //This is the defining class loader; record the statsSun.misc.PerfCounter.getParentDelegationTime (). Addtime (T1-t0); Sun.misc.PerfCounter.getFindClassTime (). Addelapsedtimefrom (t1); Sun.misc.PerfCounter.getFindClasses (). increment (); } } if(Resolve) {resolveclass (c); } returnC; } }
If the. class file with the same name is loaded before it is loaded ...
Workaround user-defined class loader
Idea 1: Rewrite loadclass () This function, whether or not loaded. Class Ask price, all reload.
@Override Public throws classnotfoundexception { System.out.println (name); byte [] data = loaderclassdata (name); return this. DefineClass (name, data, 0, data.length); };
But it was a mistake, so far it has not been understood ... Main is the class I want to load, the LoadClass () function executes two times, the second time does not know how to call the ...? Who knows, tell me, thanks!
mainjava.lang.objectjava.io.filenotfoundexception:java\lang\object. class (the system cannot find the path specified.) At Java.io.FileInputStream.open (Native Method) at Java.io.FileInputStream. <init> 53) at Com.ds.tools.MyClassLoader.loadClass ( Myclassloader.java: 78) at Java.lang.ClassLoader.defineClass1 (Native Method) At Java.lang.ClassLoader.defineClassCond (Unknown source) at Java.lang.ClassLoader.defineClass (Unknown source) at JAV A.lang.classloader.defineclass (Unknown Source) at Com.ds.tools.MyClassLoader.loadClass (Myclassloader.java: 79)
Idea 2: Can only silently rewrite the Findclass () method, the LoadClass () method will call this function, in order to avoid appclassloader check whether the class has been loaded, I put A.class's spawn location in the MyClass directory under the project root directory , In this way Myclassloader delegate appclassloader to A.class load, under the current classpath cannot find the corresponding class, unable to complete the loading of the class (same bootstraploader and Extclassloader will not be found), and ultimately we class loader to complete the loading of classes, the code is as follows:
Public classMyclassloaderextendsClassLoader {//class loader name PrivateString Loadername; //the path of the load class PrivateString Path = ""; Private FinalString FileType = ". Class"; PublicMyclassloader (String loadername) {//to make the system ClassLoader the parent loader for that class loader Super(); This. Loadername =Loadername; } PublicMyclassloader (ClassLoader parent, String loadername) {//Displays the parent loader that specifies the class loader Super(parent); This. Loadername =Loadername; } PublicString GetPath () {returnpath; } Public voidSetPath (String path) { This. Path =path; } @Override PublicString toString () {return This. Loadername; } /*** Get a byte array of the. class file *@paramname *@return */ Private byte[] Loaderclassdata (String name) {InputStream is=NULL; byte[] data =NULL; Bytearrayoutputstream BAOs=NewBytearrayoutputstream (); Name= Name.replace (".", "/"); Try{ is=NewFileInputStream (NewFile (path + name +fileType)); intc = 0; while( -1! = (c =Is.read ())) {Baos.write (c); } Data=Baos.tobytearray (); } Catch(Exception e) {e.printstacktrace (); } finally{ Try { if(Is! =NULL) Is.close (); if(BAOs! =NULL) Baos.close (); } Catch(IOException e) {e.printstacktrace (); } } returndata; } /*** Get Class object*/@Override PublicClass<?> Findclass (String name)throwsclassnotfoundexception{byte[] data =loaderclassdata (name); return This. defineclass (name, data, 0, data.length); } Public Static voidMain (string[] args)throwsclassnotfoundexception, Instantiationexception, Illegalaccessexception, SecurityException, Nosuchmethodexception, IllegalArgumentException, invocationtargetexception { for(inti=0; i<5; i++) {Myclassloader loader1=NewMyclassloader ("Myclassloader"); //String Path = new File (Myclassloader.getsystemclassloader (). GetResource (""). GetPath ()). GetParent ();Loader1.setpath ("myclass/"); Class<?> clazz = Loader1.loadclass ("Main"); System.out.println (Clazz.getname ()); } }}
Java Custom class Loader