类加载器
作用:通过类全限定名来获取二进制字节流
用例:类层次划分,OSGi,热部署,代码加密
1,类和类加载器
任意一个类和加载该类的加载器一同确立在虚拟机中的唯一性;
每个类拥有独立的类名称空间;
判断两个类是否相等,必须建立在同一个类加载器加载的前提下;否则会影响:equals, isAssignableFrom, isInstance, instanceof结果
package com.classload.temp; import java.io.IOException; import java.io.InputStream; public class MainTest { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { ClassLoader myLoader = new ClassLoader(){ @Override public Class<?> loadClass(String name) throws ClassNotFoundException { try { String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class"; InputStream is = getClass().getResourceAsStream(fileName); if(is == null){ return super.loadClass(name); } byte[] b = new byte[is.available()]; is.read(b); return defineClass(name, b, 0, b.length); } catch (IOException e) { throw new ClassNotFoundException(name); } } }; Object obj = myLoader.loadClass("com.classload.temp.MainTest").newInstance(); System.out.println(obj.getClass()); System.out.println(obj instanceof com.classload.temp.MainTest); /** * 执行结果: * class com.classload.temp.MainTest * false //obj使用了myLoader自定义类加载器,MainTest使用了应用程序类加载器,加载器不用所以为false */ } }
2,双亲委派模型
类加载器分类
方式一:①,启动类加载器: C++实现,是虚拟机自身一部分
②,其他类加载器:JAVA实现,独立于虚拟机外部,全部继承自抽象类java.lang.ClassLoader
方式二:①,启动类加载器:加载JAVA_HOME/lib目录,或被-Xbootclasspath指定路径下,并被虚拟机识别的类库加载到虚拟机内存中
启动加载器不能被用户直接引用
用户编写自定义类加载器,需要把加载请求委派给引导类加载器,自定义类加载器使用null代替即可
②,扩展类加载器:加载JAVA_HOME/lib/ext目录下,或被java.ext.dirs系统变量指定的路径下类库
扩展类加载器可以直接被用户使用
sun.misc.Launcher$ExtClassLoader实现
③,应用程序类加载器:加载用户类路径上所指定的类库
该类加载器是ClassLoader中getSystemClassLoader()方法的返回值,有名系统类加载器
该类加载器可以直接被用户使用
sun.misc.Launcher$AppClassLoader实现
类加载器之间的关系使用了组合关系复用父类加载器代码,而不是继承;
双亲委派模型工作过程:
如果一个类加载器收到类加载器的请求,首先不会自己尝试加载,而是将该请求委派给父类加载器完成,每个层次的类加载器都是如此;
因此所有类加载请求最终都传送到顶层的类加载器中,只有当父类加载器无法加载时(搜索范围内未找到该类),子加载器才会去加载。
双亲委派模型优点:
①,java类随着它的类加载器一起具备了一种带有优先级的层次关系
如:java.lang.Object存放于rt.jar中无论哪个类加载器加载该类,都会被委派到顶层启动类加载器进行加载,
因此Object类在程序的各种类加载器中都是同一个类
如:编写与rt.jar类库中同名的java类,可以正常编译但是永远无法被加载运行(因为双亲委派)
②,双亲委派模型并不是强制性的约束模型
双亲委派原理:
1,检查该类是否被加载过
2,没有加载过:
父类加载器非空:调用父类加载器的loadClass()方法,
父类加载器为空:默认使用启动类加载器作为父类加载器
父类加载器加载失败:调用自己的findClass()方法加载
3,破坏双亲委派模型