[](
)2. 双亲委派
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200512160140857.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM
【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
2MjY4MDI1,size_16,color_FFFFFF,t_70)
加载时目标的class先看自定义classloader是否加载了,如果没加载委托上一级app加载器去看看加载了没,如果没加载就继续向上挨个找,如果最顶层bootstrap也没加载,则从最顶层依次向下委派让子加载器加载这个class,如果这个class不是属于这个子加载器可以加载的范围则继续向下委派,如果最后都不能加载则抛出classNotFoundException,以上过程只要有一个找到了就直接返回结果。
面试:为什么类加载器要用双亲委派?
答:主要安全,比如说有一个java.lang.string的包要加载,如果没有双亲委派,直接拿来最低级classloader直接加载到内存使用,就把sun公司的String覆盖了,如果客户在输密码的时候我在包里做了个记录密码的手脚就很危险,而双亲委派发现string要加载那一直找到bootstrap发现sun有了,那直接把sun的string返回;次要是之前已经加载过了就不用了再加载了。
类加载器中有个parent成员变量是classloader指向谁谁就是parent。
上图中$后代表前面这个类的内部类
[](
)3. 类加载器的范围
[](
)4. 自定义类加载器
Class clazz = T005_LoadClassByHand.class.getClassLoader().loadClass(“com.testJvm.jvm.c2_classloader.T002_ClassLoaderLevel”);
上为加载类,T005…为当前类名,最后参数是你想要加载的包名.类名。
T005_LoadClassByHand.class.getClassLoader().getResourceAsStream("");
上为利用类加载器可以加载静态资源。
classLoader源码:
loadClass()方法(内部已经写好了双亲委派的过程)
上图类似递归调用,找不到就父类调用loadClass(本方法),最后也找不到就会调用findClass(),findClass方法源码中只有抛异常的一句话,是受保护的关键字修饰,具体的实现是子类中才能看到,这是钩子函数、模板函数的设计模式(写到一半,提供模板,具体子类实现)(面试设计模式可以引到classloader的源码中,加分项)!【有趣的题外话:历史上有两次jdk自己破坏了双亲委派,可以百度搜一下具体发生了啥】
自定义类加载器:
public class T006_MSBClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File f = new File(“c:/test/”, name.replace(".", “/”).concat(".class"));
try {
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while ((b=fis.read()) !=0) {
baos.write(b);
}
byte[] bytes = baos.toByteArray();
baos.close();
fis.close();//可以写的更加严谨
return defineClass(name, bytes, 0, bytes.length);//将流转换为class对象,name:类名;bytes:内存中哪部分字节数组;off:字节数组起始位置;bytes.length:字节数组结束位置。
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name); //throws ClassNotFoundException
}
public static void main(String[] args) throws Exception {
ClassLoader l = new T006_MSBClassLoader();
Class clazz = l.loadClass(“com.testJvm.jvm.Hello”);
Class clazz1 = l.loadClass(“com.testJvm.jvm.Hello”);
System.out.println(clazz == clazz1);
Hello h = (Hello)clazz.newInstance();//反射new一个对象
h.m();
System.out.println(l.getClass().getClassLoader());
System.out.println(l.getParent());
System.out.println(getSystemClassLoader());
}
}