引言
类加载器工作在加载阶段,将二进制字节流(如从Class文件中获取)加载到内存中并生成对应的java.lang.Class对象。
类的唯一标识
类的唯一标识是指同一类(类的全限定名相同)被同一个类加载器加载,判断两个类是否相等除了比较全限定名是否相同还要判断两个类是否被同一个类加载器加载。
package com.wjz.demo; import java.io.IOException; import java.io.InputStream; public class ClassLoaderTest { public static void main(String[] args) throws Exception { ClassLoader loader = new ClassLoader() { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream is = getClass().getResourceAsStream(fileName); if (is == null) return super.loadClass(name); try { byte[] bs = new byte[is.available()]; is.read(bs);
// 把二进制流字节(内容符合Class文件格式规范)组成的文件转换为一个java.lang.Class对象 return defineClass(name, bs, 0, bs.length); } catch (IOException e) { throw new ClassNotFoundException(name); } } }; Object obj = loader.loadClass("com.wjz.demo.ClassLoaderTest").newInstance(); System.out.println(obj.getClass()); System.out.println(obj instanceof com.wjz.demo.ClassLoaderTest); } }
输出结果
class com.wjz.demo.ClassLoaderTest false
结果分析
我们构造了一个类加载器去加载一个名为“com.wjz.demo.ClassLoaderTest”的类并创建了它的一个实例,但是做从属类型检查时却返回false,这是因为虚拟机中存在两个类一个是系统类加载器加载的一个我们自定义类加载器加载的,虽然都是来自同一个Class文件但是两个类不相同。
注意的是自定义的类加载器不建议重写loadClass()方法(打破双亲委派模型),而是将自己的类加载逻辑写到findClass()方法(不打破双亲委派模型)中,loadClass()方法委托父类加载如果失败则会调用自己的findClass()方法来完成加载。
双亲委派模型
工作过程是如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。