java类加载器作用:从磁盘、网络或其他来源加载class文件(字节码文件)加载到jvm内存中,并对字节码进行校验,解析和初始化,生成对应的Class对象。
class文件(字节码文件)的来源有多种
- jdk编译的class文件,先是用编辑工具(如eclipse)编写java代码;
- Jar文件,原始jar包,包含了很多class文件;
- 网络,可以从网络中加载class文件;
- jsp,jsp编译后也是生成class文件;
- 数据库中,保存在数据库中,可加密,安全性高;
- 运行时计算生成,java动态代理技术;
JVM中类加载器的树状层次结构
- 启动类加载器(Bootstrap ClassLoader):C++实现,用来加载jre核心库;
- 扩展类加载器(Extendsion ClassLoader):用来加载java扩展类库,/lib/ext目录下;
- 应用程序类加载器(Application ClassLoader):加载用户类路径上的类,classpath;
- 自定义类加载器(custom class loader):开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求;
![](https://i-blog.csdnimg.cn/blog_migrate/cea4546da6ac0d03f047e5fb48509c3a.png)
java类加载器加载类的过程分为加载,链接,初始化三步,其中链接包括验证,准备,解析等一些验证操作;
![](https://i-blog.csdnimg.cn/blog_migrate/fa8d715fec5a100ab23ebd92c7f64fac.png)
加载:通过一个类的全限定名来获取此类的二进制流,将二进制流数据转化为jvm内存运行时数据结构,做好外部引用准备;
链接:验证目的是防止字节流数据信息危害虚拟机自身安全;准备变量的初始值等,类和接口等的解析;
初始化:执行init方法;
java类加载器默认加采用的是双亲委派机制
什么是双亲委派机制?
当一个类加载器接收到一个类加载的任务时,不会立即开始加载,而是将加载任务委托给父类加载器去执行,每一层都是采用相同的方式向上委托,直到推到最顶层加载器来加载。如果父类加载器无法加载,便将加载任务退回下一级加载器去执行加载。
为什么采用双亲委派,有什么好处?
jvm认定类的实例相同有两个条件,一是同一个类产生的实例,二是由同一个类加载器所加载;同一个类由不同加载器产生的实例也不相等。所以单从这点来看我们不能自动定义一个java中已经存在的类,比如定义java.lang.String,定义java.lang.Object,因为都会是由启动类加载器加载,除非采用自定义加载器的方式。
使用双亲委派模型好处:java类随着其类加载器一起具备了一种带有优先级的层次关系,例如 java.lang.Object,无论哪一个类加载器要加载该类,最终都是委托给处于顶端的启动类加载器,因此object在程序的各种类加载器环境中都是同一个类。相反如果没有使用双亲委派模型,那么假如用户自定义了一个称为java.lang.Object的类,并放在classPath中,那么系统将会出现多个不同的Object类,则java类型体系中最基础的行为都无法保证。
简单的讲双亲委派机制能很好地解决类加载的统一性问题,保证java核心库的安全性。
对一个 Class 对象来说,如果类加载器不同,即便是同一个字节码文件,生成的 Class 对象也是不等的。也就是说,类加载器相当于 Class 对象的一个命名空间。双亲委派机制则保证了基类都由相同的类加载器加载,这样就避免了同一个字节码文件被多次加载生成不同的 Class 对象的问题。