类的加载过程

运行过程中,从磁盘到jvm内存中
类的加载全过程:加载、验证、准备、解析和初始化这五个阶段

一、加载


加载是类加载的过程的一个阶段
需要完成的是:
1、通过一个类的全限定名来获取定义此类的二进制字节流;
2、将这个字节流所表示的静态储存结构转化为方法区的运行时数据结构;
3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
相对于类加载过程的其他阶段,加载过程是开发期可控制性最强的阶段,因为可以使用系统提供的类加载器来完成,也可以由用户自定义的类加载器去完成。
加载阶段与连接阶段和部分内容是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,但这些夹杂在加载阶段之中进行的动作,仍然属于连接阶段的内容。
加载器的分类:

①    引导类加载器,由系统提供的类,C/C++语言实现
抛出的异常为 Null
Bootstrap ClassLoader
Jre/lib/rt.jar路径下的所有类
例如:String.Integer
②    扩展类加载器
抛出的异常为 Ext
Extention ClassLoader
Jre/lib/ext/…    所有.jar结尾的类
③用户自定义加载器
   AppLication  ClassLoader
   抛出的异常为 App
   classPath下的所有类,用户自定义的类

类的加载过程中,存在一个双亲委派模型:
执行过程:如果一个类加载器收到了类加载的请求,看自己之前是否加载过这个类,如果加载过,就直接返回类信息。如果没有,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,直到所有的加载请求都传送给启动类加载器,只有当父类加载器反馈自己无法加载请求的时候,子类才会去尝试加载。 

二、链接


验证:连接的第一步,为了确保class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全性,
验证过程大概分为四个阶段:文件格式验证、元数据验证、字节码验证和符号引用验证
文件格式验证:是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,是否以魔数0xCAFEBABE开头的文件类型;
元数据验证:对字节码描述的信息进行语义分析,确保Java语言规范的要求
字节码验证:进行数据流和控制流分析
符号引用验证:将符号引用转化为直接引用的时候,这个转化动作将在连接的第三个阶段—解析阶段中发生。符号引用验证可以看作是对类自身以外的信息进行匹配性的校验。
准备:正式为类变量分配内存并设置初始值的阶段,这些内存都将在方法区进行分配并赋值默认值。分配的仅包括类变量(被static修饰的变量),不包括实例变量,实例变量将在对象实例化是随着对象一起分配到Java堆中。
解析:将常量池中的符号引用被方法区中的直接引用替代
符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量,只要使用时能无歧义地定位到目标就行。与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。
直接引用:可以是直接指向目标的指针、相对偏移量或者是一个能够间接定位到目标的句柄。与虚拟机实现的内存布局相关,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。

三、初始化


类加载的最后一步。到了初始化阶段,才开始真正执行类中定义的Java程序代码(或者说是字节码)。
对类变量进行赋值操作的过程

面试


1、如果一个类的继承层次非常多,jvm慢的原因?
类的对象在第一次创建的时候,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
2、Java第一次创建对象速度比之后慢的原因
同一个类创建第二个对象的时候就不再需要加载类对象,而是直接实例化,这样后面创建的时间就短了
3、为什么要使用双亲委派模型呢?
①安全性。Java类随着它的类加载器一起具备了一种带着优先级的层次关系。如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用花自己写了一个java.lang.Object的类,并放在程序的ClassPath中,那么系统将会出现多个不同的Object类
②节约系统资源,避免类的加载重复。只要,这个类已经被加载过了,就不会在次加载。
4、为什么要有不同的类加载器?
首先,是为了区分同名的类:假定存在一个应用服务器,上面部署着许多独立的应用,同时他们拥有许多同名却不同版本的类库。试想,这时候jvm该怎么加载这些类同时能尽可能的避免掉类加载时对同名类的差异检测呢?当然是不同的应用都拥有自己独立的类加载器了。
其次,是为了更方便的加强类的能力:类加载器可以在loadclass时对class进行重写和覆盖,在此期间就可以对类进行功能性的增强。比如添加面向切面编程时用到的动态代理,以及debug等原理。怎么样达到仅修改一个类库而不对其他类库产生影响的效果呢?一个比较方便的模式就是每个类库都可以使用独立的类加载器
小结:jvm需要有不同的类加载器,因为它一方面允许你在一个jvm里运行不同的应用程序,另一方面方便你独立的对不同类库进行运行时增强。
5、判断两个类是否相等?
两个类相等,一定要注意classloader(类的加载器)是否一样
一个类只有一个class对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值