1. 加载机制的概念
类加载机制Java编译生成后的.class文件中的二进制数据读取到内存中,将其放到jvm运行时的数据区的方法区中,然后在堆区创建一个Class对象,用来封装方法区内的数据结构。
2. 类的加载过程
类的加载过程主要是加载,验证,准备,解析,初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
加载:查找并加载类的二进制数据
”加载“是”类加机制”的第一个过程,在加载阶段,虚拟机主要完成三件事:
(1)通过一个类的全限定名来获取其定义的二进制字节流
(2)将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
(3)在堆中生成一个代表这个类的Class对象,作为方法区中这些数据的访问入口。
相对于类加载的其他阶段而言,加载阶段是可控性最强的阶段,因为程序员可以使用系统的类加载器加载,还可以使用自己的类加载器加载。我们在最后一部分会详细介绍这个类加载器。在这里我们只需要知道类加载器的作用就是上面虚拟机需要完成的三件事,仅此而已就好了。

验证:此阶段主要为保证加载类的正确性
验证的主要作用就是确保被加载的类的正确性。也是连接阶段的第一步。说白了也就是我们加载好的.class文件不能对我们的虚拟机有危害,所以先检测验证一下。他主要是完成四个阶段的验证:
(1)文件格式的验证:验证.class文件字节流是否符合class文件的格式的规范,并且能够被当前版本的虚拟机处理。
(2)元数据验证:主要是对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求,比如说验证这个类是不是有父类,类中的字段方法是不是和父类冲突等等。
(3)字节码验证:这是整个验证过程最复杂的阶段,主要是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在元数据验证阶段对数据类型做出验证后,这个阶段主要对类的方法做出分析,保证类的方法在运行时不会做出危害虚拟机安全的事。
(4)符号引用验证:它是验证的最后一个阶段,发生在虚拟机将符号引用转化为直接引用的时候。主要是对类自身以外的信息进行校验。目的是确保解析动作能够完成。
对整个类加载机制而言,验证阶段是一个很重要但是非必需的阶段,如果我们的代码能够确保没有问题,那么我们就没有必要去验证,毕竟验证需要花费一定的的时间。当然我们可以使用-Xverfity:none来关闭大部分的验证。

准备:为类型分配内存并初始化为默认值
准备阶段主要为类变量分配内存并设置初始值。这些内存都在方法区分配。在这个阶段我们只需要注意两点就好了,也就是类变量和初始值两个关键词:
(1)类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中,
(2)这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值。比如
public static int value = 1; //在这里准备阶段过后的value值为0,而不是1。赋值为1的动作在初始化阶段。
当然还有其他的默认值。

注意,在上面value是被static所修饰的准备阶段之后是0,但是如果同时被final和static修饰准备阶段之后就是1了。我们可以理解为static final在编译器就将结果放入调用它的类的常量池中了。
对于final修饰的变量,会在这个阶段就直接赋值,成员变量则不会赋初始值。

解析:将字符引用解析为直接引用
解析阶段主要是虚拟机将常量池中的符号引用转化为直接引用的过程。什么是符号应用和直接引用呢?
符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量,只要是能无歧义的定位到目标就好,就好比在班级中,老师可以用张三来代表你,也可以用你的学号来代表你,但无论任何方式这些都只是一个代号(符号),这个代号指向你(符号引用)
直接引用:直接引用是可以指向目标的指针、相对偏移量或者是一个能直接或间接定位到目标的句柄。和虚拟机实现的内存有关,不同的虚拟机直接引用一般不同。
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

初始化
这是类加载机制的最后一步,在这个阶段,java程序代码才开始真正执行。我们知道,在准备阶段已经为类变量赋过一次值。在初始化阶端,程序员可以根据自己的需求来赋值了。jvm负责对类的初始化。
Java中对类变量进行初始值设定有两种方式:

①声明类变量时指定初始值
②使用静态代码块为类变量指定初始值

JVM初始化步骤:

1、假如这个类还没有被加载和连接,则程序先加载并连接该类
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类
3、假如类中有初始化语句,则系统依次执行这些初始化语句

类的初始化时机:

创建类的实例,也就是new的方式
访问某个类或接口的静态变量,或者对该静态变量赋值
调用类的静态方法
反射(如 Class.forName(“com.shengsiyuan.Test”))
初始化某个类的子类,则其父类也会被初始化
Java虚拟机启动时被标明为启动类的类( JavaTest),直接使用 java.exe命令来运行某个主类

3. 类加载器
JVM利用类加载器ClassLoader来完成类的加载,Java虚拟机中的类加载器分为两种:原始类加载器(primordial class loader)和类加载器对象(class loaderobjects)。原始类加载器是Java虚拟机实现的一部分,类加载器对象(java编写)是运行中的程序的一部分。
Java语言系统自带有三个类加载器:

Bootstrap ClassLoader:最顶层的加载类,主要加载核心类库,也就是我们环境变量下面%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。比如java -Xbootclasspath/a:path被指定的文件追加到默认的bootstrap路径中。我们可以打开我的电脑,在上面的目录下查看,看看这些jar包是不是存在于这个目录。
Extention ClassLoader:扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。
Appclass Loader:也称为SystemAppClass。 加载当前应用的classpath的所有类。

我们看到java为我们提供了三个类加载器,应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。这三种类加载器的加载顺序是什么呢?

Bootstrap ClassLoader > Extention ClassLoader > Appclass Loader


类加载的三种方式:

(1)通过命令行启动应用时由JVM初始化加载含有main()方法的主类。
(2)通过Class.forName()方法动态加载,会默认执行初始化块(static{}),但是Class.forName(name,initialize,loader)中的initialze可指定是否要执行初始化块。
(3)通过ClassLoader.loadClass()方法动态加载,不会执行初始化块。

双亲委派
JVM在类加载时默认采取双亲委派机制,如果一个类加载器接收到了类加载的请求,它首先把这个请求委托给他的父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它在搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
Java程序中区分一个类通过其全类名进行匹配,如果一个类的全类名相同就被认为是一个类,但是在JVM中识别一个类则是利用全类名+类加载器,“全类名+类加载器”被作为一个唯一的标识识别不同的类,不同的类加载器会把类放在不同的命名空间中。
双亲委派总结:

1.可以避免重复加载,父类已经加载了,子类就不需要再次加载
2.更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。

3. 类加载器
自定义类加载器两种方式:

(1)遵守双亲委派模型:继承ClassLoader,重写findClass()方法。
(2)破坏双亲委派模型:继承ClassLoader,重写loadClass()方法。 通常我们推荐采用第一种方法自定义类加载器,最大程度上的遵守双亲委派模型。

实现步骤:

(1)创建一个类继承ClassLoader抽象类
(2)重写findClass()方法
(3)在findClass()方法中调用defineClass()

package com.gsy.classloderetst;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;/*** @program: 自定义类加载器* @description:* @author: GSY* @create: 2020-03-30 11:12**/
public class ClassloderDemo extends  ClassLoader{public ClassloderDemo(){super();}public ClassloderDemo(ClassLoader parent){super(parent);}public Class<?> loderClass(String name) throws ClassNotFoundException{return super.loadClass(name);}@Overrideprotected Class findClass(String name) throws ClassNotFoundException{File file = new File("D:/HeroNode.class");try {byte[] bytes = getClassBytes(file);//利用字节数组转换成Class对象Class c = this.defineClass(name, bytes, 0, bytes.length);return c;}catch (Exception e){e.printStackTrace();}return super.findClass(name);}private byte[] getClassBytes(File file) throws Exception {FileInputStream fis= new FileInputStream(file);FileChannel fc = fis.getChannel();ByteArrayOutputStream baos= new ByteArrayOutputStream();WritableByteChannel wbc= Channels.newChannel(baos);ByteBuffer by = ByteBuffer.allocate(1024);while (true) {int i = fc.read(by);if (i == 0 || i == -1)break;by.flip();wbc.write(by);by.clear();}fis.close();return baos.toByteArray();}}

测试代码:

package com.gsy.classloderetst;/*** @program: DataStructures* @description:* @author: GSY* @create: 2020-03-30 11:12**/public class Test {public static void main(String[] args) throws Exception{ClassloderDemo classloderDemo = new ClassloderDemo(ClassLoader.getSystemClassLoader().getParent());Class<?> cc = Class.forName("com.gsy.linkedlist.HeroNode",true,classloderDemo);Object object = cc.newInstance();System.out.print(object);System.out.print(object.getClass().getClassLoader());}}

Java类加载机制,类加载过程,类加载器以及双亲委派详解相关推荐

  1. Java基础学习总结(86)——Java异常处理机制Exception抛出异常时throw和throws用法详解

    什么时运行时异常?什么是非运行时异常? 通俗的讲: 运行时异常:就是编译通过,运行时就崩了,比如数组越界. 非运行时异常:就是编译不通过,这时就得必须去处理了.不然就没法运行了. 全面的讲: Thro ...

  2. java类加载器、双亲委派、沙箱安全机制全都让你整明白(三万字,收藏慢慢啃)

    目录 一.概述 1.类加载的分类 2.类加载器的必要性 3.命名空间 4.类加载机制的基本特征 二.类加载器的分类 1.引导类加载器 2.扩展类加载器 3.系统类加载器 4.用户自定义类加载器 三.测 ...

  3. java 类加载 双亲委派_Java类加载器和双亲委派机制

    前言 之前详细介绍了Java类的整个加载过程(类加载机制详解).虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以用一句话来概括. 1)加载:查找并加载类的二进制字节流数据. 2)验证:保证被 ...

  4. 探究java-JVM的五步(三步)类加载机制(包含类加载过程的一些代码书写,如类加载代码)

    前言: 写了不少java代码,以前一直都是关心java程序跑起来后的情况步骤,今天我们就来探究一下: 在java程序还是一个个存在于静态.class文件中的类(也可以是任何被JVM认可的文件,但本质还 ...

  5. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    转载自 深入JVM系列(三)之类加载.类加载器.双亲委派机制与常见问题 一.概述 定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用 ...

  6. Android插件化开发基础之Java类加载器与双亲委派模型

    类加载器 Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需 ...

  7. 一文理类加载相关知识:类加载器、双亲委派、SPI

    思维导图 类加载的时机 类加载的流程 类从被加载到内存中开始,直到被从内存中卸载为止,它的整个生命周期包括:验证.准备.解析.初始化.使用和卸载7 个阶段. 其中验证.准备.解析 3 个部分统称为连接 ...

  8. 类加载器以及双亲委派模型

    Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制. 自JDK1.2以来,Java ...

  9. 类加载器以及双亲委派模式

    类加载器以及双亲委派模式 类加载器ClassLoader 类的加载流程的"加载"阶段是由类加载器完成的. JVM什么时候加载.class文件 当执行new操作时候 当执行Class ...

  10. JVM 类加载器与双亲委派模型

    1. 类加载器 我们知道,虚拟机在加载类的过程中需要使用类加载器进行加载,而在 Java 中,类加载器有很多,那么当 JVM 想要加载一个 .class 文件的时候,到底应该由哪个类加载器加载呢?这时 ...

最新文章

  1. 一键数据分析自动化特征工程!
  2. ★教师工资为什么这么低?/整理
  3. SpringBoot项目新建之后修改编译版本
  4. 李争——一个骨子里是极客的程序员
  5. Java的jdk在win10安装配置环境变量
  6. Java后台POST请求以application/x-www-form-urlencoded;charset=utf-8格式
  7. 夏普利模型在衡量团队成员价值中的思考
  8. astc贴图格式是什么意思_Unity 分离贴图 alpha 通道实践
  9. 计算机软件从高级语言向低级语言转换的两种方式
  10. matlab里pascal是什么意思_台球里的自然角是什么意思
  11. linux skb 存放数据,请教关于在linux网络驱动层对skb网络数据..._网络编辑_帮考网...
  12. 输入一字符串,内有数字和非数字字符,例如:A123x456 17960?302tab5876,将其中连续的数字作为一个整数,依次存放到一数组a中。例如,123放在a[0],456放在a[1]……统计有
  13. [SYZOJ279]滑♂稽♂树
  14. java+上传一个文件夹
  15. 魅魔php影视系统,魅魔全新且强大的视频电影程序(MacCMS PHP) 6.1 20120511
  16. dolphinscheduler 2.0.5 告警组件-HTTP试用及改造
  17. Oracle基础——第一章 Oracle简介
  18. HDLBits-Lemmings4
  19. python文件处理——pdf解密
  20. OSChina 周二乱弹 ——不许抽烟了,不然就分手!

热门文章

  1. scikit-learn 机器学习:sklearn.neighbors 的k近邻算法使用
  2. 微信小程序投诉页面与交互设计
  3. 根据点、旋转轴、旋转角度,计算点旋转之后的位置
  4. Chrome扩展框架-Vue项目(用vue配合webpack实现浏览器扩展,包含热更新,无需重复加载浏览器插件)
  5. windows10打开excel显示灰色的解决方案
  6. 2021-01-21:脉冲神经网络学习日志
  7. 2022-2028年中国手机银行行业市场竞争态势及未来前景分析报告
  8. 混频器/变频器的原理及分类
  9. 安卓各版本大变化(Android 6.0到10.0),兼容适配
  10. Goldendict 及其词典详述