class类加载
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了class类加载相关的知识,希望对你有一定的参考价值。
1. class文件结构
1. 魔数与Class文件的版本
Class文件头4个字节为魔数(Magic Number),为0xCAFEBABE。
紧接着4个字节为Class文件的版本号,第5、6字节为次版本号,第7、8字节为主版本号。
2. 常量池
常量池中主要存放两大类常量:字面量和符号引用。字面量比较接近于java语言层面的常量概念,如文本字符串、声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括了下面三类常量:
- 类和接口的全限定名。
- 字段名称和描述符。
- 方法的名称和描述符。
3. 访问标志
用于识别一些类或者接口层次等访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。
4. 类索引、父类索引与接口索引集合
这三项数据来确定这个类等继承关系。
5. 字段表集合
用于描述接口或者类中声明的变量。
6. 方法表集合
用于描述方法。
7. 属性表集合
2. Class文件生命周期
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
1. 加载(Loading)
此阶段完成三件事情:
- 通过一个类等全限定名来获取定义此类等二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区等运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据等访问入口。
2. 验证(Verification)
大致完成下面4个阶段等检验动作:
- 文件格式验证。
- 元数据验证。
- 字节码验证。
- 符号引用验证。
3. 准备(Preparation)
准备阶段是正式为类变量分配内存并设置类变量初始值(类型初始值)的阶段,这些变量所使用等内存都将在方法区中进行分配。
4. 解析(Resolution)
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
5. 初始化(Initialization)
根据程序员通过程序制定的主观计划去初始化类变量和其他资源,从另外一个角度去表达就是:初始化阶段是执行类构造器clinit()方法的过程。
6. 使用(Using)
7. 卸载(Unloading)
3. 类与类加载器
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话表达的更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载等前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。
这里所指的“相等”,包括代表类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法返回结果,也包括使用instanceof关键字做对象所属关系判定等情况。
4. 双亲委派模型
三种系统提供的类加载器:
1. 启动类加载器(Bootstrap ClassLoader)
这个类负责加载JAVA_HOME>lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库加载到虚拟机内存中。
2. 扩展类加载器(Extension ClassLoader)
这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JAVA_HOMElibext目录中的,或者被java.ext.dirsz系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。
3. 应用程序类加载器(Application ClassLoader)
这个加载器由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类经上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
4. 双亲委派模型过程
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
JDK1.2之后已不提倡用户再去覆盖loadClass()方法,而应当把自己的类加载逻辑写到findClass()方法中,在loadClass()方法的逻辑里如果父类加载失败,则会调用自己的findClass()方法来完成加载,这样就可以保障新写出来的类加载器是符合双亲委派规则的。
以上是关于class类加载的主要内容,如果未能解决你的问题,请参考以下文章