类加载与双亲委派模型

什么是类加载

  1. 通过一个类的全限定名将类的.class文件中的二进制数据读入到内存中
  2. 将二进制字节流所代表的静态存储结构转换为方法区的运行时数据结构
  3. 在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。

类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

类加载机制

分为5个部分:==加载,验证,准备,解析,初始化==
类加载过程
- 加载:加载是类加载过程中的一个阶段,指的是把class字节码文件从各个来源通过类加载器装载入内存中。这个阶段会在堆中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口。
- 验证:为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
- 准备:准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。进行内存分配的仅是类变量,不包括实例变量。注意这里所说的初始值概念,通常情况下为数据类型的零值。比如一个类变量定义为:

public static int v = 8080;

实际上变量v在准备阶段过后的初始值为0而不是8080,将v赋值为8080的putstatic指令是程序被编译后,存放于类构造器client方法之中。
但是注意如果声明为:

public static final int v = 8080;

在编译阶段会为v生成ConstantValue属性,在准备阶段虚拟机会根据ConstantValue属性将v赋值为8080。
- 解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。符号引用就是一组符号来描述目标,可以是任何字面量。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
- 初始化:为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
- 声明类变量是指定初始值 static int a = 1;
- 使用静态代码块为类变量指定初始值 static { a = 2;}

静态代码块,在虚拟机加载类的时候就会加载执行,而且只执行一次;
初始化阶段是执行类构造器clinit()方法的过程。clinit()是编译器自动收集类中的所有类变量和静态代码块中的语句合并而成。clinit()方法与类的构造函数不同,虚拟机会保证在子类clinit()方法执行之前,父类的clinit()方法已经执行完毕。clinit()方法并不是必需的,如果一个类中没有静态语句块,也没有对类变量的赋值操作,这个类不会生成clinit()方法。

什么时候初始化(5种情况):
1. 创建类的实例,就是new一个对象.
2. 访问类或接口的静态字段,调用静态方法。
3. 反射,对类进行反射调用
4. 初始化一个类的子类
5. JVM启动时,虚拟机会初始化主类(包含main()方法的那个类)

类加载器与双亲委派模型

类加载器
  • 通过一个类的全限定名来获取描述此类的.class文件中的二进制字节流这个动作的代码模块
  • 它在JVM外部,==以便让应用程序自己决定如何去获取所需要的类==。
  • 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性。即要比较两个类是否”相等”,只有这两个类是由同一类加载器加载的前提下才有意义,否则即使这两个类来源于同一个class文件,被同一虚拟机加载,只要加载他们的类加载器不同,这两个类必不相等。

  • 从虚拟机角度,只存在两种不同的类加载器:启动类加载器(Bootstrap ClassLoader),它使用C++语言实现,是虚拟机自身的一部分。另一种是所有其他的类加载器,它们由java语言实现,独立于虚拟机外部,都继承自抽象类java.lang.ClassLoader.

  • 从java开发人员角度,3种系统提供的类加载器。
    • ==启动类加载器==(Bootstrap ClassLoader)它负责将存放在\lib目录中的(或-Xbootclass指定的路径),将JVM自身工作所需要的类(java核心API,C++实现)加载到虚拟机中。
    • ==扩展类加载器==(Extension ClassLoader)负责加载\lib\ext目录中(或java.ext.dirs),为扩展API,开发者可以直接使用扩展类加载器。
    • ==应用程序加载类==(Application ClassLoader)称为系统加载器,他负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器。如果应用程序中没有自定义的类加载器,他就是程序中默认的类加载器。
      类加载器
双亲委派模型

Parents Delegation Model 直译过来叫双亲,其实并不存在双这个字眼。
- 双亲委派模型表示了类加载器之间的层次关系
- 特点:==除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器==。这里类加载器之间的父子关系一般使用组合关系来复用父加载器的代码。
- 双亲委派模型的==工作过程==:类加载器收到类加载请求,它会把这个请求委派给父类加载器去完成,而不是自己。每一层的类加载器都是如此。因此所有的类加载请求最终都会传到顶层的启动类加载器中,如果父类加载器可以完成类加载任务,就成功返回,只有当父类加载器反馈自己无法完成这个加载请求时(它的搜索范围没有找到所需的类),子加载器才会尝试自己加载。
- ==双亲委派模式优点==:
- Java类随着它的类加载器一起具备了一种带有优先级的层次关系,避免重复加载。如Object类在程序的各个加载器环境中都是同一个类,因为它都会被委派给最顶层的启动类加载器进行加载。
- 实现简单。双亲委派的代码集中在java.lang.ClassLoader的==loadClass()方法==中。它先检查是否已经被加载过,若没有被加载过则调用父类加载器的loadCLass()方法,如父类加载器为空则默认使用启动类加载器作为父类加载器。如果父类加载失败,抛出ClassNotFoundException再调用自己的findClass()方法进行加载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值