1.类加载子系统的作用
加载 —> 链接 —> 初始化
- 类加载子系统只负责从文件系统或者网络中加载Class文件, Class文件在文件开口有特定的文件标识
- ClassLoader只负责加载class文件 , 至于它是否可以运行,则由Execution Engine决定的
- 加载信的类信息存放在方法区的内存空间, 除了类的信息以外, 还会存放运行时所需要的常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息时Class文件中常量池部分的内存映射)
2.类加载器ClassLoader角色
- class file存在本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM中的,
- class file加载到JVM中,被称之为DNA元数据模板,放在方法区
- 在.class文件—> JVM —> 最终成为元数据模板,此过程就是一个运输过程(类装载器Class Loader)
3.类的加载过程
4.类加载器分类
JVM支持两种类型的类加载器, 分别为引导类加载器(Boostrap ClassLoader)和自定义类加载器(User Defined ClassLoader)
1.引导类加载器
启动类加载器(Bootstrap ClassLoader)
- 这个类使用C/C++语言实现,嵌套在JVM内部
- 他用来加载Java的核心库
- 并不继承java.lang.ClassLoader, 没有父加载器
- 出于安全考虑,Bootstrap启动类加载器只加载包名java, javax, sun等开头的类
- 加载扩展类和应用程序加载类,并指定为他们的父类加载器
-XX:+TraceClassLoading
2.扩展类加载器
扩展类加载器(Extension ClassLoader)
- Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
- 继承ClassLoader
- 父类加载器为启动类加载器
- 从java.ext.dirs系统属性所指定的的目录中加载类库,或者从JDK的安装目录下jre/lib/ext 子目录下加载类库,如果用户创建的jar也放在此目录下,也会自动有扩展类加载器加载.
3.系统类加载器
系统类加载器(System ClassLoader)
- Java语言编写, 由sun.misc.Launcher$AppClassLoader实现
- 继承于ClassLoader类
- 父类加载器为扩展加载器
- 它负责加载环境变量classpath或者系统属性java.class.path指定类路径下的类库
- 应用程序中的类加载器默认是系统类加载器
- 它是用户自定义类加载器的默认加载器
- 通过ClassLoader的getSystemClassLoader方法可以获取到改类加载器
4.双亲委派机制
Java虚拟机对Class文件才用的是按需加载的方式,也就是说需要使用该类的时才会将它的class文件加载到内存生存class对象 , 而某个加载类的class文件时,Java虚拟机采用的是双亲委派机制,即把请求交个父类加载器处理,他是一种任务委派模式
- 工作原理
1) 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行
2) 如果父类加载器上面还有父类加载器,则会进一步向上委托,依次递归,直到最后一个加载器
3) 如果父类加载器可以加载成功就会返回, 如果父类加载器不能加载成功就会交给子类加载器去加载,然后返回, 这就是双亲委派机制
- 优势
- 避免重复的类加载
- 保护程序安全,防止核心API被篡改
5.沙箱安全机制
自定义String类, 但是在加载的自定义的String类的时候, 会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar中的java/lang/String.class), 报错信息说没有main方法, 就是因为加载的是rt.jar包中的String类,这样可以保证对java核心源代码的保护,这就是沙箱安全机制
- 在JVM中表示两个class对象是否为同一个类存在两个必要的条件,
- 类的完整类名必须一致, 包括包名
- 加载这个类的ClassLoader(ClassLoader实例对象)必须相同.
6.对类加载器的引用
JVM必须知道一个类型是由启动加载器加载还是由用户类加载器加载的. 如果一个类型是由用户加载器加载的, 那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中,当解析一个类型到另外一个类型的引用的时候, JVM需要保证这两个类型的类加载器是相同的
7.类的主动使用和被动使用
- 主动使用
- 创建类的实例
- 访问某个类或者接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(比如: Class.forName(“com.andav.info.Test”))
- 初始化一个类的子类
- Java虚拟机启动的时候被标明为启动类的类
- Java7开始支持的动态语言
- java.lang.invoke.MethodHandle实例解析的结果REF_getStatic REF_putStatic REF_invokeStatic句柄对应类的没有初始化,则初始化
- 被动使用
- 除了以上几种情况, 其他情况都可以被视作为类的被动使用,不会导致类的初始化