ClassLoader是整個JVM運行機制的入口,程序通過ClassLoader將編譯好的字節碼文件加載到內存中,生成Class,進而創建對象,之後才能進行各種運算、解析,最終生成機器碼提交到操作系統中;
ClassLoader的作用是將字節碼文件加載到內存中,所以要先有字節碼文件
1、創建java文件
public class FileJava {
public FileJava() {
System.out.println("hhehhehe");
}
}
特別需要注意的是:
該文件不能在idea中創建,否則會在運行程序的時候被編譯到用戶類路徑(classpath)下,那麼還是會被AppClassLoader加載;
而且如果將其建立在IDEA中,在編譯完該文件之後,其class文件會存在於該項目的src同等階級的out/production/目錄下,如果使用的是該class路徑,運行時也會報java.lang.NoClassDefFoundError錯誤;
我將該文件建立在了D盤下的ClassLoaderBySelf文件夾下;
2、編譯java文件爲字節碼文件
使用命令:javac FileJava.java
3、創建自定義ClassLoader,並繼承ClassLoader
ClassLoader具體的工作流程主要是通過兩個方法完成類加載的,分別是findClass和defineClass;
findClass根據路徑加載字節碼文件,然後交給defineClass,再把字節碼文件轉化爲class。
自定義ClassLoader需要開發者對findClass方法進行重寫,完成加載字節碼文件的操作,之後再將字節數據傳給ClassLoader的defineClass方法即可;
import java.io.*;
public class MyClassLoader extends ClassLoader {
private String myPath;//文件路徑
public MyClassLoader( String myPath) {
this.myPath = myPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
//name是文件名
String classPath=myPath+name+".class";
//System.out.println(classPath);
InputStream in=null;
ByteArrayOutputStream out=null;
try {
in = new FileInputStream(classPath);
out=new ByteArrayOutputStream();
int value=-1;
while ((value=in.read())!=-1){
out.write(value);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(out!=null){
out.close();
}
if(in!=null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] bytes= out.toByteArray();
return defineClass(name,bytes,0,bytes.length);
}
}
4、進行測試
實例化MyClassLoader,並通過該實例化對象加載字節碼文件獲取Class對象
public class Test {
public static void main(String[] args) {
MyClassLoader myClassLoader=new MyClassLoader("D:/ClassLoaderBySelf/");
try {
Class classz=myClassLoader.loadClass("FileJava");
System.out.println(classz);
System.out.println(classz.getConstructor().newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
截圖: