您好,登錄后才能下訂單哦!
Java中怎么自定義一個類加載器,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
一 點睛
1 ClassLoader類有如下兩個關鍵方法:
loadClass(String name, boolean resolve):該方法為ClassLoader的入口點,根據指定的二進制名稱來加載類,系統就是調用ClassLoader的該方法來獲取指定類對應的Class對象。
findClass(String name):根據二進制名稱來查找類。
如果需要實現自定義的ClassLoader,可以通過重寫以上兩個方法來實現,當然我們推薦重寫findClass()方法,而不是重寫loadClass()方法。
2 自定義類加載器常用功能
執行代碼前自動驗證數字簽名。
根據用戶提供的密碼解密代碼,從而可以實現代碼混淆器來避免反編譯class文件。
根據用戶需求來動態地加載類。
根據應用需求把其他數據以字節碼的形式加載到應用中。
二 實戰
1 CompileClassLoader.java
import java.io.*;import java.lang.reflect.*;public class CompileClassLoader extends ClassLoader{ // 讀取一個文件的內容 private byte[] getBytes(String filename) throws IOException { File file = new File(filename); long len = file.length(); byte[] raw = new byte[(int)len]; try( FileInputStream fin = new FileInputStream(file)) { // 一次讀取class文件的全部二進制數據 int r = fin.read(raw); if(r != len) throw new IOException("無法讀取全部文件:" + r + " != " + len); return raw; } } // 定義編譯指定Java文件的方法 private boolean compile(String javaFile) throws IOException { System.out.println("CompileClassLoader:正在編譯 " + javaFile + "..."); // 調用系統的javac命令 Process p = Runtime.getRuntime().exec("javac " + javaFile); try { // 其他線程都等待這個線程完成 p.waitFor(); } catch(InterruptedException ie) { System.out.println(ie); } // 獲取javac線程的退出值 int ret = p.exitValue(); // 返回編譯是否成功 return ret == 0; } // 重寫ClassLoader的findClass方法 protected Class<?> findClass(String name) throws ClassNotFoundException { Class clazz = null; // 將包路徑中的點(.)替換成斜線(/)。 String fileStub = name.replace("." , "/"); String javaFilename = fileStub + ".java"; String classFilename = fileStub + ".class"; File javaFile = new File(javaFilename); File classFile = new File(classFilename); // 當指定Java源文件存在,且class文件不存在、或者Java源文件 // 的修改時間比class文件修改時間更晚,重新編譯 if(javaFile.exists() && (!classFile.exists() || javaFile.lastModified() > classFile.lastModified())) { try { // 如果編譯失敗,或者該Class文件不存在 if(!compile(javaFilename) || !classFile.exists()) { throw new ClassNotFoundException( "ClassNotFoundExcetpion:" + javaFilename); } } catch (IOException ex) { ex.printStackTrace(); } } // 如果class文件存在,系統負責將該文件轉換成Class對象 if (classFile.exists()) { try { // 將class文件的二進制數據讀入數組 byte[] raw = getBytes(classFilename); // 調用ClassLoader的defineClass方法將二進制數據轉換成Class對象 clazz = defineClass(name,raw,0,raw.length); } catch(IOException ie) { ie.printStackTrace(); } } // 如果clazz為null,表明加載失敗,則拋出異常 if(clazz == null) { throw new ClassNotFoundException(name); } return clazz; } // 定義一個主方法 public static void main(String[] args) throws Exception { // 如果運行該程序時沒有參數,即沒有目標類 if (args.length < 1) { System.out.println("缺少目標類,請按如下格式運行Java源文件:"); System.out.println("java CompileClassLoader ClassName"); } // 第一個參數是需要運行的類 String progClass = args[0]; // 剩下的參數將作為運行目標類時的參數, // 將這些參數復制到一個新數組中 String[] progArgs = new String[args.length-1]; System.arraycopy(args , 1 , progArgs , 0 , progArgs.length); CompileClassLoader ccl = new CompileClassLoader(); // 加載需要運行的類 Class<?> clazz = ccl.loadClass(progClass); // 獲取需要運行的類的主方法 Method main = clazz.getMethod("main" , (new String[0]).getClass()); Object[] argsArray = {progArgs}; main.invoke(null,argsArray); }}
2 Hello.java
public class Hello{ public static void main(String[] args) { for (String arg : args) { System.out.println("運行Hello的參數:" + arg); } }}
3 運行
E:\Java\瘋狂java講義\codes\18\18.2>java CompileClassLoader Hello
看完上述內容,你們掌握Java中怎么自定義一個類加載器的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。