第二章:类加载子系统

第二章:类加载子系统

类加载子系统的作用:

① 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识
② ClassLoader只负责class文件的加载,至于它是否可以运行,则由执行引擎(Execution Engine)决定
③ 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

类加载器ClassLoader的角色:


类的加载过程:


类的加载过程一:Loading

加载:①通过一个类的全限定名获取定义此类的二进制字节流
②将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
③在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

类的加载过程二:Linking

类的加载过程三:Initialization

类加载器分类:

JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。
从概念上说,自定义类加载器一般指的是程序中由开发人员自定义的一类 类加载器,但是Java虚拟机规范中没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器。
在程序中常见的类加载器始终只有3个:如下所示

表达的是包含关系(也可以理解成上下级关系),不是继承关系,也不是上层下层关系。
JDK实现中的继承关系:

引导类、扩展类、系统类加载器使用演示:

① 引导类加载器

② 扩展类加载器

③ 应用程序类加载器

为什么需要用户自定义的类加载器?

实现步骤:

ClassLoader的常用方法以及获取方法:

ClassLoader类是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类/引导类加载)

方法名称 描述
getParent() 返回该类加载器的超类加载器
loadClass(String name) 加载名称为name的类,返回结果为java.lang.Class的类的实例
findClass(String name) 查找名称为name的类,返回结果为java.lang.Class的类的实例
findLoadedClass(String name) 查找名称为name的已经加载过的类,返回结果为java.lang.Class类的实例
defineClass(String name,byte[] b,int off,int len) 把字节数组b中的内容转换为一个java类,返回结果为java.lang.Class类的实例
resolveClass(Class<?>c) 连接指定的一个java类

获取ClassLoader的途径:

双亲委派机制:

Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要用该类时才将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。
工作原理:

使用举例:

双亲委派机制的优势:
① 避免类的重复加载
② 保护程序安全,防止核心API被篡改
a) 比如举的例子中,自己定义个一个java.lang包,下面有String类,在运行的时候,因为使用了双亲委派机制,会将加载类的这个操作逐级向上委托,直到引导类加载器发现它可以加载java.lang包中的类,则由它接管,真正的去加载官方的java.lang.String而不是我们自定义的这个String类。
b) 在自定义的java.lang包中定义一个shkstart类,当运行的时候,会报错:

沙箱安全机制:

类的主动使用与被动使用等:
在JVM中表示两个class对象是否为同一个类存在两个必要条件:
① 类的完整名称必须一致,包括包名
② 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。

对类加载器的引用:
JVM必须知道一个类型是由引导类加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用时,JVM需要保证这两个类的类加载器是相同的。

这个初始化指的是类的加载过程中的最后一个阶段:初始化阶段

posted @ 2020-05-24 21:44  scnb  阅读(92)  评论(0)    收藏  举报