什么是ClassLoader
ClassLoader简称类加载器,主要用于加载和校验编译后的Java文件(即:以.class结尾的文件);
有哪些类加载器(ClassLoader)
AppClassLoader(应用类加载器)
ExtClassLoader(扩展类加载器注意:JDK1.8后被修改为平台类加载器)
BootstrapClassLoader(启动类加载器)
获取类加载器
通过简单的demo来得到类加载器
public class User {
public static void main(String[] args) {
User user = new User();
Class<? extends User> userClass = user.getClass();
System.out.println(userClass.getClassLoader());
System.out.println(userClass.getClassLoader().getParent());
System.out.println(userClass.getClassLoader().getParent().getParent());
}
}
结果显示:
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
null
这里涉及到底层所以返回null
类加载器的加载顺序
由于当前的类加载器使用双亲模式
首先加载系统类加载器,此时系统类加载器会判断当前类是否已近是当前系统已定的类,如果是加载系统类,不会初始化被加载的类,不存在则由ExtClassLoader加载
ExtClassLoader检测加载,一般都是lib包中,不存在则交给AppClassLoader加载
AppClassLoader检测加载类,当前应用加载器会从当前应用中(就是启动类或者整个程序中)查找需要加载的类,存在即加载程序的类,不存在交给用户定义的类加载器处理
使用双亲模式的好处,可以保护Java程序的安全,防止非法的加载Class
用户可以使用自定义类加载器用来实现对不同位置的类的加载和调用
mkdir -p aa/bb
vim aa/bb/Hello.java
javac aa/bb/Hello.java
Hello.java 代码
package aa.bb;
public class Hello {
static {
System.out.println("init ...");
}
}
自定义类加载器
mkdir -p aa/classloader
vim aa/classloader/MyClassLoader.java
javac -Xlint:deprecation aa/classloader/MyClassLoader.java
MyClassLoader.java 代码
package aa.classloader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
private String path;
public MyClassLoader(String path) {
this.path = path;
}
@Override
public Class<?> findClass(final String name) throws ClassNotFoundException {
final String classPath = path + "/" + name.replace(".","/") + ".class";
try (InputStream in = new FileInputStream(classPath);
ByteArrayOutputStream out = new ByteArrayOutputStream();) {
int len;
byte[] bytes = new byte[4096];
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
byte[] byteArray = out.toByteArray();
return defineClass(name, byteArray, 0, byteArray.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
创建测试类 HelloTest.java
mkdir -p aa/test
vim aa/test/HelloTest.java
javac aa/test/HelloTest.java
package aa.test;
import aa.classloader.MyClassLoader;
public class HelloTest {
public static void main(String[] args) throws Exception {
String path = HelloTest.class.getClassLoader().getResource("./").getPath();
MyClassLoader myClassLoader = new MyClassLoader(path);
Class<?> clazz = myClassLoader.findClass("aa.bb.Hello");
clazz.newInstance();
}
}
运行结果
java aa.test.HelloTest
init ...
总结:
1.使用自定义的类加载器的时候需要继承ClassLoader来实现class的加载
2.在加载的过程中须要使用 ByteArrayOutputStream 内存流
3.解析的时候需要使用父类来解析获得二进制信息以此得到Class的信息(必须调用 super.defineClass(fileName, classBytes, 0, classBytes.length);)
4.使用自定义的类加载器可以没有限制的在其他的地方加载类
参考
Java中自定义ClassLoader和ClassLoader的使用非
https://blog.csdn.net/weixin_45492007/article/details/98875060
网友评论