Java 自定义 ClassLoader 实现 JVM 类加载
定義需要加載的類
為了能夠?qū)崿F(xiàn)類加載,并展示效果,定義一個Hello類,再為其定義一個sayHello()方法,加載Hello類之后,調(diào)用它的sayHello()方法。
public?class?Hello?{public?static?void?sayHello(){System.out.println("Hello,I?am?....");} }定義類加載器
自定義加載器,需要繼承ClassLoader,并重寫里面的protected Class?findClass(String name) throws ClassNotFoundException方法。
import?java.io.File; import?java.io.FileInputStream; import?java.io.IOException; import?java.lang.reflect.Method; import?java.nio.MappedByteBuffer; import?java.nio.channels.FileChannel; import?java.nio.channels.FileChannel.MapMode;public?class?MyClassLoader?extends?ClassLoader?{/***?重寫父類方法,返回一個Class對象*?ClassLoader中對于這個方法的注釋是:*?This?method?should?be?overridden?by?class?loader?implementations*/protected?Class<?>?findClass(String?name)?throws?ClassNotFoundException?{Class?clazz?=?null;String?classFilename?=?name?+?".class";File?classFile?=?new?File(classFilename);if?(classFile.exists())?{try?(FileChannel?fileChannel?=?new?FileInputStream(classFile).getChannel();)?{MappedByteBuffer?mappedByteBuffer?=?fileChannel.map(MapMode.READ_ONLY,?0,?fileChannel.size());byte[]?b?=?mappedByteBuffer.array();clazz?=?defineClass(name,?b,?0,?b.length);}?catch?(IOException?e)?{e.printStackTrace();}}if?(clazz?==?null)?{throw?new?ClassNotFoundException(name);}return?clazz;}public?static?void?main(String[]?args)?throws?Exception{MyClassLoader?myClassLoader?=?new?MyClassLoader();Class?clazz?=?myClassLoader.loadClass(args[0]);Method?sayHello?=?clazz.getMethod("sayHello");sayHello.invoke(null,?null);} }編譯需要加載的類文件
類加載的時候加載的是字節(jié)碼文件,所以需要預(yù)先把定義的Hello類編譯成字節(jié)友文件。
javac?Hello.java驗證字節(jié)碼文件是否編譯成功,利用二進制文件查看器查看我們編譯之后的文件,樣式如下:
0000000?177312?137272?000000?032000?016000?000012?000006?004416 0000020?007400?010000?000010?005021?011000?011400?000007?003424 0000040?012400?000001?036006?067151?072151?000476?001400?024450 0000060?000526?002000?067503?062544?000001?046017?067151?047145 0000100?066565?062542?052162?061141?062554?000001?071410?074541 0000120?062510?066154?000557?005000?067523?071165?062543?064506 0000140?062554?000001?044012?066145?067554?065056?073141?006141 0000160?003400?004000?000007?006026?013400?014000?000001?044017 0000200?066145?067554?044454?060440?020155?027056?027056?000007 0000220?006031?015000?015400?000001?044005?066145?067554?000001 0000240?065020?073141?027541?060554?063556?047457?065142?061545 0000260?000564?010000?060552?060566?066057?067141?027547?074523 0000300?072163?066545?000001?067403?072165?000001?046025?060552 0000320?060566?064457?027557?071120?067151?051564?071164?060545 0000340?035555?000001?065023?073141?027541?067551?050057?064562 0000360?072156?072123?062562?066541?000001?070007?064562?072156 0000400?067154?000001?024025?065114?073141?027541?060554?063556 0000420?051457?071164?067151?035547?053051?020400?002400?003000 0000440?000000?000000?001000?000400?003400?004000?000400?004400 0000460?000000?016400?000400?000400?000000?002400?133452?000400 0000500?000261?000000?000001?000012?000000?000006?000001?000000 0000520?000002?000011?000013?000010?000001?000011?000000?000045 0000540?000002?000000?000000?131011?001000?001422?000266?130404 0000560?000000?000400?005000?000000?005000?001000?000000?002000 0000600?004000?002400?000400?006000?000000?001000?006400 0000616編譯自定義的類加載器并執(zhí)行程序
//編譯代碼 javac?MyClassLoader.java //當(dāng)然我們也可以同時編譯我們所有的java源文件 javac?*.java執(zhí)行成功之后,我們用下面的語句執(zhí)行代碼,測試是否成功,并查看結(jié)果
java?MyClassLoader?Hello //運行結(jié)果 Hello,I?am?....當(dāng)程序按照預(yù)期顯示,就證明我的自定義類加載器成功了。
總結(jié)
通過上面的程序代碼,簡單的實現(xiàn)JVM的類加載過程,知道了程序運行的一點流程。但是在編寫的時候有如下坑需要注意
-
類文件不需要指定包,否則加載的時候我們需要額外的處理,把包中的"."替換成文件系統(tǒng)的路徑"/"。
-
需要加載的Hello類中的反射調(diào)用的方法要用static修飾,這樣invoke的時候第一個參數(shù)才可以使用null關(guān)鍵字代替,否則需要創(chuàng)建一個對應(yīng)的類實例。
官方文檔中有這樣一句話If the underlying method is static, then the specified obj argument is ignored. It may be null.
總結(jié)
以上是生活随笔為你收集整理的Java 自定义 ClassLoader 实现 JVM 类加载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线下门店场景化互动类产品浅析
- 下一篇: Integer判断相等,到底该用==还是