Java基礎(chǔ)之自定義類加載器
一、類加載器關(guān)系

自定義類加載器
創(chuàng)建一個類繼承ClassLoader類,同時重寫findClass方法,用于判斷當(dāng)前類的class文件是否已被加載
二、基于本地class文件的自定義類加載器
本地class文件路徑

自定義類加載器:
//創(chuàng)建自定義加載器類繼承ClassLoader類
public class MyClassLoader extends ClassLoader{
// 包路徑
private String Path;
// 構(gòu)造方法,用于初始化Path屬性
public MyClassLoader(String path) {
this.Path = path;
}
// 重寫findClass方法,參數(shù)name表示要加載類的全類名(包名.類名)
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println("findclass方法執(zhí)行");
// 檢查該類的class文件是否已被加載,如果已加載則返回class文件(字節(jié)碼文件)對象,如果沒有加載返回null
Class<?> loadedClass = findLoadedClass(name);
// 如果已加載直接返回該類的class文件(字節(jié)碼文件)對象
if (loadedClass != null){
return loadedClass;
}
// 字節(jié)數(shù)組,用于存儲class文件的字節(jié)流
byte[] bytes = null;
try {
// 獲取class文件的字節(jié)流
bytes = getBytes(name);
} catch (Exception e) {
e.printStackTrace();
}
if (bytes != null){
// 如果字節(jié)數(shù)組不為空,則將class文件加載到JVM中
System.out.println(bytes.length);
// 將class文件加載到JVM中,返回class文件對象
Class<?> aClass = this.defineClass(name, bytes, 0, bytes.length);
return aClass;
}else {
throw new ClassNotFoundException();
}
}
// 獲取class文件的字節(jié)流
private byte[] getBytes(String name) throws Exception{
// 拼接class文件路徑 replace(".",File.separator) 表示將全類名中的"."替換為當(dāng)前系統(tǒng)的分隔符,F(xiàn)ile.separator返回當(dāng)前系統(tǒng)的分隔符
String FileUrl = Path + name.replace(".", File.separator) + ".class";
byte[] bytes;
// 相當(dāng)于一個緩存區(qū),動態(tài)擴(kuò)容,也就是隨著寫入字節(jié)的增加自動擴(kuò)容
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
File file = new File(FileUrl);
// 創(chuàng)建輸入流
InputStream inputStream = new FileInputStream(file);
int content;
// 循環(huán)將輸入流中的所有數(shù)據(jù)寫入到緩存區(qū)中
while ((content = inputStream.read()) != -1){
arrayOutputStream.write(content);
arrayOutputStream.flush();
}
bytes = arrayOutputStream.toByteArray();
return bytes;
}
}
測試類


三、遇到的問題
在獲取class文件字節(jié)流的getBytes方法中,為什么不將輸入流中的所有數(shù)據(jù)直接寫入到bytes中,而是要先寫入到ByteArrayOutputStream中?如下:

現(xiàn)在我們嘗試將數(shù)據(jù)直接寫入到bytes中,如下:

但在運(yùn)行時報錯:
Extra bytes at the end of class file com/smallsweets/OutSide

這是為什么呢?個人理解如下:
看報錯提示Extra bytes at the end of:在文件的最后有多余的字節(jié)
查看class文件的大小

但是字節(jié)數(shù)組在初始化時指定的大小是1024,多余位置的字節(jié)是0,所以就出現(xiàn)了多余字節(jié)的情況
解決方法是:我們可以在初始化數(shù)組時將數(shù)組的大小指定為和class文件相同大小,如下:

這樣就可以解決了,雖然可以解決,但如果每次加載類時都要修改未免有些麻煩,所以這里我們直接使用ByteArrayOutputStream,因?yàn)樗莿討B(tài)擴(kuò)容的,也就是大小是隨寫入數(shù)據(jù)的多少而動態(tài)變化的不會出現(xiàn)多余字節(jié)的情況
四、基于網(wǎng)絡(luò)(url)class文件的自定義類加載器
class文件路徑

自定義類加載器:
public class MyUrlClassLoader extends ClassLoader {
private String Path;
public MyUrlClassLoader(String path) {
this.Path = path;
}
// 參數(shù)name表示全類名(包名.類名)
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 判斷該類的class文件是否已加載,已加載直接返回class文件對象,沒有加載返回null
Class<?> loadedClass = this.findLoadedClass(name);
if (loadedClass != null){
return loadedClass;
}
byte[] bytes = null;
try {
// 獲取網(wǎng)絡(luò)class文件的字節(jié)數(shù)組
bytes = getBytes(Path);
} catch (Exception e) {
e.printStackTrace();
}
// 如果字節(jié)數(shù)組不為空,將class文件加載到JVM中
if (bytes != null){
// 將class文件加載到JVM中,參數(shù)(全類名,字節(jié)數(shù)組,起始位置,長度)
Class<?> aClass = this.defineClass(name, bytes, 0, bytes.length);
return aClass;
}else {
throw new ClassNotFoundException();
}
}
// 獲取網(wǎng)絡(luò)class文件的字節(jié)流,參數(shù)為class文件的url
private byte[] getBytes(String fileUrl) throws Exception {
byte[] bytes;
// 創(chuàng)建url對象
URL url = new URL(fileUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 連接url
httpURLConnection.connect();
// 創(chuàng)建輸入流,獲取網(wǎng)絡(luò)中class文件的字節(jié)流
InputStream inputStream = httpURLConnection.getInputStream();
// 相當(dāng)于緩存區(qū),動態(tài)擴(kuò)容
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
int content;
// 循環(huán)將輸入流中的所有數(shù)據(jù)寫入到緩存區(qū)中
while ((content = inputStream.read()) != -1){
arrayOutputStream.write(content);
arrayOutputStream.flush();
}
bytes = arrayOutputStream.toByteArray();
return bytes;
}
}
測試類


到此這篇關(guān)于Java基礎(chǔ)之自定義類加載器的文章就介紹到這了,更多相關(guān)Java自定義類加載器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于JAVA中stream流的基礎(chǔ)處理(獲取對象字段和對象批量處理等)
這篇文章主要介紹了關(guān)于JAVA中stream流的基礎(chǔ)處理,包含獲取對象字段、按字段排序、按字段去重、對象批量處理、指定字段轉(zhuǎn)數(shù)組等內(nèi)容,需要的朋友可以參考下2023-03-03
基于java ssm springboot實(shí)現(xiàn)選課推薦交流平臺系統(tǒng)
這篇文章主要介紹了選課推薦交流平臺系統(tǒng)是基于java ssm springboot來的實(shí)現(xiàn)的,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08
spring boot 實(shí)現(xiàn)熱部署的幾種方式及配置方法
這篇文章主要介紹了spring boot 實(shí)現(xiàn)熱部署的幾種方式及配置方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2025-05-05
Netty學(xué)習(xí)教程之Netty與Marshalling結(jié)合發(fā)送對象
Netty是由JBOSS提供的一個Java開源框架,之前已經(jīng)給大家簡單介紹了一些基礎(chǔ)與使用,下面這篇文章主要給大家介紹了關(guān)于Netty與Marshalling結(jié)合發(fā)送對象的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-05-05

