- 虚拟机把描述类的数据从class文件加载到内存,并且对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制。
- 类的生命周期:加载,连接(验证,准备,解析),初始化,使用,卸载。
其中解析阶段的顺序不一致,她在某些情况下可以初始化之后再解析。 - 加载阶段发生的事情:
3.1 通过一个类的全限定名来获取定义此类的二进制字节流。
3.2 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.3 在内存中生成一个代表这个类的class对象,作为方法区中这个类的各种数据的访问入口。 - 验证阶段是为了保证class文件中的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全(因为class文件可以从多个途径获得,可能就有数组越界啊,对象转换类型失败等问题),验证过程发生的事情:
4.1 文件格式验证(验证字节流是否符合Class文件格式的规范)(这个阶段是基于二进制字节流进行的,下面的就是基于方法区的存储结构进行的)
4.2 元数据验证(对字节码描述的信息进行语义分析,保证符合java语言规范)(类是否有父类,父类是否可继承,就是从整体来看的)
4.3 字节码验证(通过对数据流和控制流分析,确保语义是合法的,符合逻辑的)(是针对方法体来说的:例如方法中的类型转换时有效的)
4.4 符号引用验证(发生在虚拟机将符号引用转换为直接引用的时候)(通过字符串描述的全限定名能否找到类,在指定类中是否存在符合方法的字段,符号引用中的类方法等的访问性时候可以被当前类访问) - 准备阶段是为类变量分配内存并且设置类变量初始值的过程,这些变量所使用的内存将在方法区中进行分配,没有被final修饰的初始值为0,被final修饰的初始值就是他的真实值。
- 解析阶段是把常量池类的符号应用替换为直接引用的过程,下面介绍四种解析过程:
6.1 类或者接口的解析:
假设类D中有对N的引用,那么解析N的过程如下:第一步如果N不是数组类型,虚拟机就会把表示N的全限定类名传递给D的类加载器去加载这个类N,但是在加载这个类的过程中,可能由于元数据验证,字节码验证的需要又触发了其他相关类的加载动作,一旦出现异常,解析失败。第二步是如果N是数组,并且数组的元素类型为对象,那么就会按照第一步的规则去加载对象类型,接着由虚拟机生成一个代表此数组维度和元素的数组对象。第三步是确保D对N是否有访问权,没有就抛出IllegalAccessError。
6.2 字段解析
第一步首先解析字段所属的类或者接口C,如果出现异常,解析失败。第二步是如果C中包含了名称和字段类型都匹配的字段,则返回引用,查找结束。第三步是如果第二步没有查找成功,如果C实现了接口,将会自下向上递归搜索接口和胡接口,如果接口中找到了,返回引用,查找结束。第四步,如果c是一个类,将会自下向上递归搜索,找到就返回直接引用,查找结束。第五步,查找失败,抛出NoSuchFieldError。如果查找到了,要对字段访问权限进行验证。
6.3 类方法解析
第一步首先解析方法所属的类C;第二步是在类中查找有没有这个方法;第三步是在类的父类中递归查找有没有这个方法;第四步是在类实现的接口中递归查找;第五步查找失败,抛出NoSuchMethodError。如果找到了,要对类方法进行访问权限验证。
6.4 接口方法解析
第一步首先解析方法所属的类C,第二步如果发现c是个类,直接报错;第三步在接口中查找方法;第四步在接口的父接口中递归查找;第五步查找失败。因为接口方法默认都是public的,不存在访问权限的问题。 - 初始化阶段是类加载过程的最后一步,就是真正的开始执行java代码。即初始化阶段完成的static变量的赋值和static代码块的操作。
- 类加载器就是一个代码模块,实现的功能是(通过一个全限定名获取到描述此类的二进制字节流文件)。
- 启动类加载器(BootStrap ClassLoader)加载java_home/lib下的类库加载到虚拟机内存中;扩展类加载器(Extension ClassLoader)加载java_home/lib/ext下的类库到虚拟机内存中,开发者可以直接使用;应用程序类加载器(Application ClassLoader)加载用户类路径(ClassPath)上指定的类库,开发者可以直接使用这个类库。
10.双亲委派模型:除了顶层的启动类加载器外,其余的类加载器都有自己的父类加载器。工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载请求都被传送到了顶层的启动类加载器中。只有当父类加载器反馈自己无法完成这个加载请求时,子类加载器才会尝试着自己去加载。
11.双亲委派模型的好处:加载的类随着她的类加载器有了一种带有优先级的层次关系,例如object最终会交给启动类加载器去完成,这样保证object类在任何类加载器下被加载都是同一个类,避免了多个类的情况。
12.加载的过程:首先判断类有无被加载过,没有的话,传给她的父类加载器加载,为空的话直接交给启动类加载器加载;如果父类加载器不能加载,再有自身的findclass来加载.
类加载机制
最新推荐文章于 2022-12-07 23:54:33 发布