用.class文件建立對象

第一步:  給你一個編譯好的class文件以及它的包名,建立一個對象出來。java

      1)class文件源代碼數組

      

Java代碼   收藏代碼
  1. package com.wsc.classloader;  
  2.   
  3. public class Tool{  
  4.   
  5.     public void print() {  
  6.     }  
  7. }  

    2)使用javac Tool.java 編譯成class文件ide

 

    3)將Tool.class文件讀取到內存中,生成byte[]數組加密

    

Java代碼   收藏代碼
  1. /** 
  2.  * 加載class文件 
  3.  *  
  4.  * @param clazzPath 
  5.  *            class絕對文件路徑 
  6.  * @return 字節數組 
  7.  * @throws IOException 
  8.  */  
  9. private byte[] loadClassFile(String clazzPath) throws IOException {  
  10.     FileInputStream fis = new FileInputStream(clazzPath);  
  11.     BufferedInputStream bis = new BufferedInputStream(fis);  
  12.     ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  13.   
  14.     byte[] buffer = new byte[1024 * 256];  
  15.     int ch = 0;  
  16.     while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {  
  17.         baos.write(buffer, 0, ch);  
  18.     }  
  19.     return baos.toByteArray();  
  20. }  

      4)自定義ClassLoader,使用ClassLoader中的defineClass方法:protected final Class<?> defineClass(String name, byte[] b, int off, int len)。參數分別是類名稱,class文件對應的字節數組,起始位置和終止位置。spa

     

Java代碼   收藏代碼
  1. @Override  
  2. protected Class<?> loadClass(String name, boolean resolve)  
  3.         throws ClassNotFoundException {  
  4.     Class<?> c = findLoadedClass(name);  
  5.     if (c == null) {  
  6.         c = defineClass(name, data, 0, data.length);  
  7.     }  
  8.     return c;  
  9. }  

 總體代碼是:調試

Java代碼   收藏代碼
  1. package com.wsc.classloader;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.FileInputStream;  
  6. import java.io.IOException;  
  7.   
  8. public class ClassLoaderOne extends ClassLoader {  
  9.   
  10.     public static void main(String[] args) throws Exception {  
  11.   
  12.         ClassLoaderOne loader = new ClassLoaderOne(  
  13.                 "E:\\JAVA\\JAVAFX\\ClassLoader\\libs\\Tool.class");  
  14.         Class<?> clazz = loader.loadClass("com.wsc.classloader.Tool");  
  15.         Object o = clazz.newInstance();  
  16.         System.out.println(o.getClass().getClassLoader());  
  17.   
  18.     }  
  19.   
  20.     private byte[] data;  
  21.   
  22.     public ClassLoaderOne(String clazzPath) throws IOException {  
  23.         data = loadClassFile(clazzPath);  
  24.     }  
  25.   
  26.     /** 
  27.      * 加載class文件 
  28.      *  
  29.      * @param clazzPath 
  30.      *            class絕對文件路徑 
  31.      * @return 字節數組 
  32.      * @throws IOException 
  33.      */  
  34.     private byte[] loadClassFile(String clazzPath) throws IOException {  
  35.         FileInputStream fis = new FileInputStream(clazzPath);  
  36.         BufferedInputStream bis = new BufferedInputStream(fis);  
  37.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  38.   
  39.         byte[] buffer = new byte[1024 * 256];  
  40.         int ch = 0;  
  41.         while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {  
  42.             baos.write(buffer, 0, ch);  
  43.         }  
  44.         return baos.toByteArray();  
  45.     }  
  46.   
  47.     @Override  
  48.     protected Class<?> loadClass(String name, boolean resolve)  
  49.             throws ClassNotFoundException {  
  50.         Class<?> c = findLoadedClass(name);  
  51.         if (c == null) {  
  52.             c = defineClass(name, data, 0, data.length);  
  53.         }  
  54.         return c;  
  55.     }  
  56.   
  57. }  

 感受是這樣的,跑一下:對象

Java代碼   收藏代碼
  1. Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang  
  2.     at java.lang.ClassLoader.preDefineClass(Unknown Source)  
  3.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  4.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  5.     at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)  
  6.     at java.lang.ClassLoader.loadClass(Unknown Source)  
  7.     at java.lang.ClassLoader.defineClass1(Native Method)  
  8.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  9.     at java.lang.ClassLoader.defineClass(Unknown Source)  
  10.     at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)  
  11.     at java.lang.ClassLoader.loadClass(Unknown Source)  
  12.     at com.wsc.classloader.ClassLoaderOne.main(ClassLoaderOne.java:14)  

   意思是:禁止加載名爲java.lang的包。blog

   緣由是:雖然Tool類中沒有使用任何引入java.lang下類,可是它的父類Object是在java.lang下的,classloader加載Tool類時會把它全部的關係網都加載出來才行,父類Object確定是要加載的。接口

   這樣就簡單了!無非多寫一個If else.使用父加載器(類加載器都有一個父類加載器)加載便可。內存

  

Java代碼   收藏代碼
  1. @Override  
  2. protected Class<?> loadClass(String name, boolean resolve)  
  3.         throws ClassNotFoundException {  
  4.     Class<?> c = findLoadedClass(name);  
  5.     if (name.equals("java.lang.Object")) {  
  6.         ClassLoader parent = getParent();  
  7.         c = parent.loadClass(name);  
  8.     }  
  9.     if (c == null) {  
  10.         c = defineClass(name, data, 0, data.length);  
  11.     }  
  12.     return c;  
  13. }  

   跑一下結果是:

  

Java代碼   收藏代碼
  1. com.wsc.classloader.ClassLoaderOne@ca470  

  第二步:新的問題

    

Java代碼   收藏代碼
  1. Method[] methods = clazz.getMethods();  
  2. for (int i = 0; i < methods.length; i++) {  
  3.     String name = methods[i].getName();  
  4.     System.out.println(name);  
  5.     Class<?>[] params = methods[i].getParameterTypes();  
  6.     for (int j = 0; j < params.length; j++) {  
  7.         System.out.println(params[j].toString());  
  8.     }  
  9. }  

   這個時候仍是會報剛纔的錯誤,由於Method類也在java.lang包下,只能在增長一個If else.

   顯然,代碼應該這樣寫

   

Java代碼   收藏代碼
  1. @Override  
  2. protected Class<?> loadClass(String name, boolean resolve)  
  3.         throws ClassNotFoundException {  
  4.     Class<?> c = findLoadedClass(name);  
  5.     if (c == null) {  
  6.         // 若是父加載器不爲null,使用父類加載器加載(好比Object,HashMap等核心類)  
  7.         if (getParent() != null) {  
  8.             try {  
  9.                 c = getParent().loadClass(name);  
  10.             } catch (Exception e) {  
  11.                 // 父類可能沒加載,則拋異常  
  12.             }  
  13.   
  14.         }  
  15.         // 若是父類加載器沒有加載,再使用自定義加載器加載  
  16.         if (c == null) {  
  17.             c = defineClass(name, data, 0, data.length);  
  18.         }  
  19.     }  
  20.   
  21.     return c;  
  22. }  

   打印結果:

  

Java代碼   收藏代碼
  1. toString  
  2. print  
  3. class java.lang.String  
  4. getClass  
  5. hashCode  
  6. equals  
  7. class java.lang.Object  
  8. notify  
  9. notifyAll  
  10. wait  
  11. long  
  12. int  
  13. wait  
  14. wait  
  15. long  
  16. com.wsc.classloader.ClassLoaderOne@fcfa52  

   第三步:若是本地能夠經過.class文件建立,遠程固然也已同一個道理(若是須要加密,在本地多一個解密便可)。若是class文件是遠程調用的話,本地通常使用接口或者反射兩種方法調用。首選是接口,反射一是效率,而是要清楚全部的方法名稱、參數名稱過於麻煩。

  因爲遠程加載class文件到本地,若是出錯很難定位出錯位置。幸虧,classloader使用規則默認是根據URLClassLoader來使用的,會先根據檢查本地是否有該類,因此能夠直接將源碼放在本地便可調試,固然發佈的時候必定要刪除。

   如圖:

    經過這個基本的入門程序能夠了解ClassLoader的基本流程。
    

   1

相關文章
相關標籤/搜索