JAVA的类加载过程

我们详细讲解一下Java虚拟机中类加载的全过程,也就是加载、验证、准备、解析和初始化这5个阶段所执行的具体动作。

一、加载
“加载”是”类加载”(Class Loading)过程的一个阶段,希望读者没有混淆这两个看起来很相似的名词。在加载阶段,虚拟机需要完成以下3件事情:

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

二、验证
验证阶段大致上会完成下面4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证。

1) 文件格式验证
第一阶段要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。这一阶段可能包括下面这些验证点:
. 是否以魔数0xCAFEBABE开头。
. 主、次版本号是否在当前虚拟机处理范围之内。
. 常量池的常量中是否有不被支持的常量类型(检查常量tag标志)。口指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
. CONSTANT Utf8info型的常量中是否有不符合UTF8编码的数据。
. Class文件电各个部分及文件本身是否有被删除的或附加的其他信息。

2) 元数据验证
第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java 语言规范的要求,这个阶段可能包括的验证点如下:
. 这个类是否有父类(除了java.lang.Object之外,所有的类都应当有父类)。
. 这个类的父类是否继承了不允许被继承的类(被final修饰的类)。
. 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。
. 类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,或者出现不符合规则的方法重载,例如方法参数都一致,但返回值类型却不同等)。

3) 字节码验证
第三阶段是整个验证过程中最复杂的一个阶段,主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在第二阶段对元数据信息中的数据类型做完校验后,这个阶段将对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机安全的事件

4) 符号引用验证
最后一个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三阶段——解析阶段中发生。符号引用验证可以看做是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,通常需要校验下列内容:
. 符号引用中通过字符串描述的全限定名是否能找到对应的类。
. 在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。
. 符号引用中的类、字段、方法的访问性(private、protected、public、default)是否可被当前类访问。

三、准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这个阶段中有两个容易产生混淆的概念需要强调一下,首先,这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。其次,这里所说的初始值”通常情况”下是数据类型的零值,假设一个类变量的定义为:
publicstatic int value=123;
那变量value在准备阶段过后的初始值为0而不是123,因为这时候尚未开始执行任何Java方法,而把value 赋值为123的putstatic 指令是程序被编译后,存放于类构造器

上面提到,在”通常情况”下初始值是零值,那相对的会有一些”特殊情况”:如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量value就会被初始化为ConstantValue属性所指定的值,假设上面类变量value的定义变为:
public static final int value=123;

编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123。

四、解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,符号引用在前一章讲解Class文件格式的时候已经出现过多次,在Class文件中它以CONSTANT_Class info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现,那解析阶段中所说的直接引用与符号引用又有什么关联呢?
. 符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。各种虚拟机实现的内存布局可以各不相同,但是它们能接受的符号引用必须都是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
. 直接引用(Direct References):直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在内存中存在。

解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄
和调用点限定符7类符号用进行,分别对应于常量池的CONSTANT-Class info、CONSTANT Fieldref info、CONSTANT_Methodref info-CONSTANT_InterfaceMethodref info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info 和CONSTANT InvokeDynamic_infoT种常量类型。

五、初始化

类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说是字节码)。
在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器

Original: https://www.cnblogs.com/mrhgw/p/14510080.html
Author: 有容乃大
Title: JAVA的类加载过程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/538000/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Java字符串处理:随机字符串,提取数字,身份证号码

    一、随机字符串 /** * * @param count 随机字符串&…

    Java 2023年6月5日
    062
  • Java StringBuffer 和 StringBuilder 类区别

    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。 和 String 类不同的是,StringBuffer 和 StringBuil…

    Java 2023年5月29日
    063
  • Java8 提供的流式操作

    参考资料 流式操作 Stream 代表一个支持串行或并行聚集操作的元素序列。 filter filter 生成一个新的 Stream,该 Stream 所有元素都满足 predic…

    Java 2023年6月9日
    075
  • 认识RocketMQ4.x架构设计

    消息模型 单体的消息模型 RocketMQ消息模型跟其他的消息队列一样 都是 producer – > topic->consumer producer 生…

    Java 2023年6月16日
    077
  • 线程不安全

    众所周知,多线程访问同一公共资源会带来线程的不安全,本文探讨一下这个问题的若干细节。 关于线程安全的基本问题 有关线程安全常涉及两个概念: 竞态条件:当两个线程竞争同一资源时,如果…

    Java 2023年5月30日
    068
  • CentOS7-ElasticSearch的使用

    1.下载 ElasticSearch官方下载地址​www.elastic.co/cn/downloads/past-releases#elasticsearch 最好选择版本7.x…

    Java 2023年6月7日
    076
  • 泛型

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月7日
    076
  • winform子线程修改界面控件的值

    示例代码 //代理:是应用程序向OS申请执行的一个函数;这里只给出了函数的"形" delegate void delSetText(TextBox txt, s…

    Java 2023年5月30日
    076
  • 创建vue项目

    使用命令行创建vue项目时候要以管理员身份运行,否则可能会报错 安装element插件 在idea中导入vue项目,使用终端npm run serve 来运行vue项目 Origi…

    Java 2023年6月7日
    067
  • synchronized下的 i+=2 和 i++ i++执行结果居然不一样

    逛【博客园-博问】时发现了一段有意思的问题: 这段代码是这样的: import java.util.concurrent.ExecutorService; import java….

    Java 2023年6月8日
    081
  • 拜托,面试官别问我「位图」了

    这是之前面试的时候面试官问到过的一个问题,今天正好看到 布隆过滤器,写篇文章总结一下 我们先看一下流程,流程懂了,问题就解决 90%了 我们都知道一个 int 占 4字节,一个字节…

    Java 2023年6月9日
    092
  • 使用idea将整个项目打包为公共组件到本地maven库

    1、在idea工程右侧找到mavenproject Original: https://www.cnblogs.com/holly8/p/16642361.htmlAuthor: …

    Java 2023年6月14日
    076
  • JSP学习笔记

    jsp的全称是java server pages。其主要作用是代替Servlet程序回传html页面的数据。 JSP的本质 JSP页面本质是一个Servlet程序。当我们第一次访问…

    Java 2023年6月8日
    075
  • 漏洞发现:代码分析引擎 CodeQL

    codeql 是一门类似 SQL 的查询语言,通过对源码(C/C++、C#、golang、java、JavaScript、typescript、python)进行完整编译,并在此过…

    Java 2023年6月7日
    0227
  • Java轻松实现,每天给对象发情话!

    一、引言 最近看到一篇用js代码实现表白的文章,深有感触。然后发现自己也可以用java代码实现,然后就开始写代码了,发现还挺有意思的,话不多说开搞实现思路: 使用HttpClien…

    Java 2023年6月5日
    085
  • 面试题:sleep() 和 wait()的区别?

    1.相同点: 一旦执行方法,都可以使得当前的线程进入阻塞状态。 2.不同点: 1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()2…

    Java 2023年6月14日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球