1.class loader是什么?
负责将java字节码.class文件加载入jvm,生成Class对象,存入内存,才能使用(new),才可以创建该Class的Obj对象。
2.class loader工作包含哪些流程?
1、装载:查找和导入Class文件
2、链接:其中解析步骤是可以选择的
(a)检查:检查载入的class文件数据的正确性
(b)准备:给类的静态变量分配存储空间
(c)解析:将符号引用转成直接引用
3、初始化:对静态变量,静态代码块执行初始化工作
3.有哪些默认class loader
1、 Bootstrap ClassLoader 启动类加载器,jvm自带 c语言编写,无java源码,负责加载jdk核心jar。
2、 ExtClassLoader 扩展类加载器,负责加载jdk中ext文件夹下class。
3、 AppClassLoader 应用类加载器,负责加载应用程序项目class加载。
4.默认类加载器如何协调工作。
新加载任务->到3号->传递2号->传递1号
1号有,不加载,没有传递给2号
2号有,不加载,没有传递给3号
3号有,不加载,3号没有,加载。
5.核心方法
1、 loadClass(String name,boolean resovle ) 加载class入口
2、 findClass(String name) 查询class文件跟defineClass连用
3、 defineClass(String name,byte[] data,int off,int length) 将class文件字节数据载入内存
6.demo
import java.io.*;
import java.util.concurrent.TimeUnit;
public class MyClassLoader extends ClassLoader {
// window系统存放地址
private static final String WIN_ROOT_DIR = "D:\\plugins";
// linux系统存放地址
private static final String LIN_ROOT_DIR = "/home/java/plugins";
/**
* 加载class对象
* 默认实现为 先去父loader找,找到就不加载,找不到才在自己这找
* 若要实现替换旧的,就不能先去父loader找,因为在app loader中可能已经存在,
* 这样就不会再加载。所以要先在自己这找,找不到才去父里找。
*
* @param name
* @param resolve
* @return
* @throws ClassNotFoundException
*/
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> result = findClass(name);
if (result == null) {
return super.loadClass(name, resolve);
}
if (resolve) {
resolveClass(result);
}
return result;
}
/**
* 寻找class文件所在并调用defineClass方法加二进制文件载入内存。
*
* @param name 加package的Class名
* @return
* @throws ClassNotFoundException
*/
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = loadByte(name);
if (data == null) {
return null;
}
return defineClass(name, data, 0, data.length);
}
/**
* 获取class文件存放根路径
*
* @return
*/
private static String getRootDir() {
if (File.separatorChar == '\\') {
return WIN_ROOT_DIR;
}
return LIN_ROOT_DIR;
}
/**
* 将class文件转为byte[]
*
* @param name
* @return
*/
private byte[] loadByte(String name) {
if (null == name || name.isEmpty()) {
return null;
}
StringBuilder builder = new StringBuilder(name);
for (int index = builder.indexOf("."); index != -1; index = builder.indexOf(".")) {
builder.replace(index, index + 1, File.separator);
}
String uri = builder + ".class";
String url = getRootDir() + File.separator + uri;
File file = new File(url);
if (!file.exists()) {
return null;
}
try (FileInputStream input = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] temp = new byte[1024];
for (int index = input.read(temp); index != -1; index = input.read(temp)) {
out.write(temp, 0, index);
}
out.flush();
return out.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// 测试
public static void main(String[] args) throws ClassNotFoundException,
IllegalAccessException, InstantiationException, InterruptedException {
while (true) {
MyClassLoader loader = new MyClassLoader();
Class<?> clazz = loader.loadClass("Test", true);
Object o = clazz.newInstance();
System.out.println(o);
TimeUnit.SECONDS.sleep(1);
}
}
}
测试类Test,只要重写toString()返回不同的字符串值即可。