类加载器子系统

1:类加载器子系统和加载过程

在这里插入图片描述
类加载器子系统,包括加载阶段(主要由类加载器操作),链接阶段,和初始化阶段

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

类加载器的角色:

这里插入图片描述
Class文件存在本地硬盘上,可以理解为设计师画在纸上的模板,而最终在执行的时候,是要加载到JVM中来根据这个文件实例化出N个一模一样的实例。
Class file加载到JVM中,被称为DNA元数据模板,放在方法区。
在Class文件–>JVM–>元数据模板。这个过程中,需要一个运输工具(类加载器)来执行
流程如下:
在这里插入图片描述
在这里插入图片描述

加载过程:

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

补充:加载class文件的方式
从本地系统中直接加载
通过网络获取,比如:web Applet
从zip包中读取,成为日后jar,war格式的基础
运行时计算生成,比如使用动态代理技术
从加密文件中获取,典型的防Class文件被反编译的保护措施

链接过程:

 1)验证(Verify)
       目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
       主要包括四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证
 2)准备(Prepare)
        为类变量分配内存并且设置该类变量地默认初始值,即零值
        这里不包含用final修饰地static,因为final在编译时候就会分配了(写代码的时候,不赋值,编译就过不了),准备阶段会显式初始化
        也不会为实例变量分配初始化值,类变量会分配在方法区中,实例变量会随着对象一起,分配到java堆中
 3)解析(Resolve)
        将常量池的符号引用转换成直接引用的过程
        事实上,解析操作,往往会伴随着jvm在执行完初始化以后再执行。

初始化过程:

   就是执行类的构造器方法<clinit>()的过程,也就是执行静态变量的显式初始化,和执行静态代码块的过程
   此过程javac编译器,会自动收集类中的所有的类变量的赋值动作和静态代码快中的语句合并而来
   一个类的<clinit>()方法在多线程下,是被同步加锁的

类加载器的分类:

JVM的支持的两种加载器:1:引导类加载器   2:  自定义类加载器
狭义的自定义类加载器理解:由用户根据特定需求实现,继承自java.lang.ClassLoader或其子类。
但是,严格来说
Java虚拟机规范,将派生于抽象类ClassLoader的类加载器,都划分为自定义类加载器,包括扩展类和系统类加载器

常用的三个:引导类加载器  :2:自定义类加载器( 扩展类加载器  系统类加载器)

在这里插入图片描述
父类,和父类加载器,是两个不同的概念
比如:
扩展类加载器的父类:java.net.URLClassLoader
扩展类加载器的父类加载器:引导类加载器(Bootstrap Class Loader)
上图的类加载器,是包含关系,不是继承关系,也不是上下层关系

引导类加载器

使用C/C++实现,嵌套在JVM内部
它来加载Java的核心类库(JAVA_HOME/jre/lib/rt.jar,resources.jar或者 sun.boot.class.path路径下内容),用于提供JVM自身所需类
并不继承于java.lang.ClassLoader,也没有父类加载器
出于安全考虑,只加载包名为java,javax,sun等开头的类

扩展类加载器

java语言编写,派生于ClassLoader类,父类加载器为引导(启动)类加载器
从java.ext.dirs系统属性所指定的目录中加载类库
或者从JDK安装目录的jre/lib/ext子目录下加载类库
如果用户创建的jar放在此目录下,也会由扩展类加载器加载

应用(系统)类加载器

java语言编写,派生于ClassLoader类,父类加载器为扩展类加载器
负责加载环境变量classpath或者是系统属性java.class.path指定路径下的类库
该类是程序中默认的加载器,一般来说,java应用的类都是由它来加载的
通过ClassLoader的getSystemclassLoader()方法可以获取到该类加载器

用户自定义的类加载器

一般来说,java的开发工作,上述三个类加载器基本就可以完成,但是在一些架构设计,中间件设计的时候,
有时候需要自己开发一些类加载器
作用主要是为了 隔离加载类,修改类的加载方式,扩展加载源,防止源码泄露等等,99.9的程序员用不到,具体实现步骤不做赘述

双亲委派机制

java虚拟机对class文件是按需加载的方式,也就是说,当需要使用该类的时候,才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,java虚拟机采取的是双亲委派模式,即把加载请求交由父类加载器
流程:
1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类加载器去加载
2)如果父类加载器还有其父类加载器,则进一步向上委托,依次递归,最终到达顶层的引导类加载器
3)如果父类加载器可以完成加载任务,就返回成功,如果父类加载器无法完成,自己类加载才会自己去加载
在这里插入图片描述
作用:避免了类的重复加载,保护了核心api不受侵害
比如:
我自定义了一个java.lang包,在此包下定义了String,那如果我在别的地方new了Sting对象
那么:1)系统类加载器,把加载请求给了扩展类加载器,扩展类加载器又给了引导类加载器
2)引导类加载器发现,Sting,在rt.jar的java/lang/String.class,然后他就给加载了
3)加载完,返回加载的消息,然后系统类加载器收到消息,自己也不加载了
4)结果,加载的还是核心api的String,跟自定义的没关系

其他:如何判断两个对象是同一个类的对象
1:类的完整类名必须一致,包括包名
2:加载这个类的类加载器必须是一个

  • 54
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值