JVM篇之类加载机制
创始人
2024-06-01 02:59:04
0

目录

      • JVM篇之类加载机制
        • 类加载过程
          • 1.加载
          • 2.验证
          • 3.准备
          • 4.解析
          • 5.初始化
        • 类加载器
        • 类的加载
        • 双亲委派模型

JVM篇之类加载机制

类加载过程

JVM类的加载过程分为五个部分:加载,验证,准备,解析,初始化,其中验证,准备,解析三个部分统称为连接。如下图所示

在这里插入图片描述

1.加载
  1. 通过一个类的全限定名来获取其定义的二进制字节流,将二进制数据读入内存,放入运行时数据区的方法区中。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在堆区创建一个代表这个类的java.lang.Class对象,用来封装类在方法区内的数据结构,作为对方法区中这些数据的访问入口。

我的理解:加载的最终结果是在堆中创建了一个Class对象,这个对象是独一无二的。
Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
具体关于Class对象的内容可以查看反射相关内容。

class Car{}
public class Loading {public static void main(String[] args) {Car car1 = new Car();Car car2 = new Car();Car car3 = new Car();Class car1Class = car1.getClass();Class car2Class = car2.getClass();Class car3Class = car3.getClass();System.out.println("car1:"+car1 +" car2:"+car2 +" car3:"+car3);//car1:Car@15aeb7ab car2:Car@7b23ec81 car3:Car@6acbcfc0System.out.println("car1Class:"+car1Class +"; car2Class:"+car2Class +"; car3Class:"+car3Class);//car1Class:class Car; car2Class:class Car; car3Class:class CarSystem.out.println(car1Class==car2Class);//trueSystem.out.println(car1Class.getClass());//class java.lang.Class}
}

我的理解:java中最抽象的类是java.lang.Class,而Car类对象(car1Class)可以看作是java.lang.Class类的一个实例化对象
与此相对应的,我们可以把car1对象看作是Car类的一个实例化对象。堆的唯一目的就是存放对象实例。

加载.class文件的方式

  1. 将Java源文件动态编译为.class文件
  2. 从zip压缩包读取,成为日后jar ,war格式的基础
  3. 从本地系统中直接加载
    • Class findSystemClass(String name): 方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用 defineClass 将原始字节转换成 Class 对象,以将该文件转换成类。
  4. 通过网络下载.class文件
  5. 从专有数据库中提取.class文件
2.验证

确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。大概分为4个阶段的检验动作:

  1. 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以 0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。

  2. 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了 java.lang.Object之外。

  3. 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

  4. 符号引用验证:确保解析动作能正确执行。

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用 -Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

3.准备

准备阶段是正式为类的静态变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。

注意:

  1. 只会为被static关键字修饰的静态成员变量设置初始值
    • 可以来思考一下为什么:静态成员变量可以通过类名直接调用,因此应该先于类的实例化设置初始值。
  2. 这里所设置的初始值如果不被final修饰,则是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
  3. 对final的静态字面值常量直接赋初值,即字面值

例如:

public static int a=100;//准备阶段设为0
public static final int b=100;//准备阶段设为100
4.解析

把类中的符号引用转换为直接引用
在编译时,java类并不知道引用类的实际地址,所以用符号引用来代替。在该阶段转换为实际内存地址。

5.初始化

初始化主要完成静态块执行以及静态变量的赋值.
先初始化父类,再初始化当前类.
只有对类主动使用时才会初始化.

触发初始化的条件有:

  1. 创建类的实例时
  2. 访问类的静态方法或静态变量的时候
  3. 使用Class.forName反射类的时候
  4. 或者某个子类初始化的时候

JVM初始化步骤

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

类加载器

虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类,JVM 提
供了 3 种类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)。如下图所示:

在这里插入图片描述

先看一个例子

class Car{}
public class Loading {public static void main(String[] args) {Car car = new Car();ClassLoader classLoader1 = car.getClass().getClassLoader();System.out.println(classLoader1);System.out.println(classLoader1.getParent());System.out.println(classLoader1.getParent().getParent());}
}

运行结果

jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
jdk.internal.loader.ClassLoaders$PlatformClassLoader@4eec7777
null

java9开始,将Bootstrap ClassLoader—>Platform ClassLoader
PlatformClassLoader的父类是null的原因:BootstrapClassLoader是用c语言实现的。

应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。因为JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,因此如果编写了自己的ClassLoader,便可以做到如下几点:

  1. 在执行非置信代码之前,自动验证数字签名。
  2. 动态地创建符合用户特定需要的定制化构建类。
  3. 从特定的场所取得java class,例如数据库中和网络中。

类的加载

类加载有三种方式:

  1. 命令行启动应用时候由JVM初始化加载
  2. 通过Class.forName()方法动态加载
  3. 通过ClassLoader.loadClass()方法动态加载

Class.forName()和ClassLoader.loadClass()区别

  • Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
  • ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
  • Class.forName(name,initialize,loader)带参函数也可控制是否加载static块。

双亲委派模型

双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

优点:

  1. 避免类的重复加载
  2. 避免Java的核心API被篡改

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...