一、基本类加载机制介绍

大体引用一下《深入理解Java虚拟机》一书中对类加载的定义:虚拟机将描述类的二进制字节流(即Class文件)加载到内存中,并对其进行验证、准备、解析、初始化,最终

生成可以直接被虚拟机使用的Java类型(即已经校验合格且有clinit执行完clinit方法的Class对象),这就是JVM的类加载机制。

一个好的定义,就应该是这样准确而简练的。下面先罗列一下类的生命周期:

加载  ->  验证  ->  准备 ->  解析  ->  初始化  ->  使用  -> 卸载

其中加载、验证、准备、初始化、卸载一定会严格按照上面的顺序进行。既然知道了类加载的大体流程,那么问题来了,什么时候会触发类的加载呢?

虚拟机规范中并未作出明确的要求,但是会要求有且仅有下面五种情况发生的时候,会触发类的初始化(言外之意就是初始化之前的动作必须在此之前完成),这五种情况分别为:

1、遇到new、getStatic、putStatic、invokeStatic字节码指令时;

2、通过java.lang.reflect包对类进行反射调用的时候;

3、初始化子类时,如果父类没初始化,则先初始化父类(接口除外,接口初始化规则是调用哪个接口初始化哪个,不看继承关系);

4、虚拟机启动时,会自动初始化带有main方法的类;

5、使用动态语言支持时,如果一个MethodHandle实例最后的解析结果是REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄且对应的类未初始化时(恕BZ学识浅薄,目前还没

理解这种情况对应实际代码中的哪种情形,只能先放放,好在这东西一般也遇不到 (><) )。

额外需要说明两点,这两点也经常在那种仿佛是考脑筋急转弯的编程题中遇到:一是在new一个引用类数组时不会触发这个类的初始化;二是对于常量的引用不会触发类初始化(static final)。

尤其是第二点要特别说明一下,如果A类中有一个常量叫VALUE,B类中引用了这个常量,那么在编译的时候,编译器会把这个VALUE直接放入B类的运行时常量池中供其后续使用,就是说在

编译之后,A类与B类已经没有任何交互了,所以也就不会触发初始化了。

二、类加载的各个过程简介

1、加载

类加载的第一个阶段叫加载,主要做的是三步:

1)、通过类的全限定名定位到对应的class文件;

2)、将二进制字节文件转化为方法区中的运行时数据;

3)、在内存中生成一个Class对象,作为方法区中访问运行时数据(即访问2)中数据)的入口。

此阶段自由度较高,我们可以自定义一个类加载器,加载class文件

2、验证

验证主要包括四部分:文件格式校验、源数据校验(包括语义校验)、字节码校验、字符引用校验

3、准备

在此阶段,虚拟机会为类变量(即static修饰的成员变量)分配内存并赋初始的默认值。例如一个类变量private static int a = 2,在此阶段中,会给赋初值,即a=0。实际的2这个值是在

初始化阶段赋予。而如果是static final类型的变量,在此阶段会直接赋终值。

4、解析

将要加载的那个类的运行时常量池内的符号引用替换为直接引用

5、初始化

初始化的过程就是执行类构造器<clinit>()方法的过程。此方法是在编译阶段由编译器收集类中的静态变量赋值动作、静态方法、静态块的语句合并而成的。

虚拟机会保证执行<clinit>()方法前会先执行父类的<clinit>方法,同样如果是接口则不用先执行父类的类构造器。

三、类加载器

Java中一共定义了三种类加载器:启动类加载器  <--   扩展类加载器   <--  应用程序类加载器,继承关系如箭头所示,而我们自定的类加载器,都是以应用程序类加载器为父类。

类加载器很重要,因为JVM中定义两个类是不是同一个类,只用两个判断条件:一个是类的全限定名是否相同,另一个是加载这个类的类加载器是否相同。如果类加载器不同,

即使类的全限定名一样,虚拟机一样会判定这是两个不同的类。

Java中的类加载器加载类,采用双亲委派模型,即类加载器C要加载类A时,会先让父加载器去加载,一直往上传递,除非父类加载器中搜不到这个类,才会让子类去加载,并且

每个类只能被加载一次。这样做的好处就是可以限定核心类不会被替换篡改。比如一种常见的面试题,如果你重新编写了一个路径为java.lang.String的类,能否调用到这个自定的类

中的方法?在这里很明显答案是不会,因为JVM中已经加载了那个系统的java.lang.String类,当用应用程序类加载器加载我们自定义的String类时,由于双亲委派模型的存在,加载

任务会被委派给父类,一直往上传递,最后到启动类加载器那里,然后发现已经加载过一次这个全路径名的类了,不能重复加载,所以自定义的String类就无法被加载调用了。(有没

有发现这个剧情跟真假美猴王很相似,一直传递到佛祖那,才辨别出了真假 。。。)

类加载就暂时到这里,书中还提到一些双亲委派模型被破坏的场景,由于了解的不够透彻,就先不乱发言了。学习之路,还是要坚持死磕啊,加油!

JVM的类加载的更多相关文章

  1. JVM学习一:JVM之类加载器概况

    18年转眼就3月份都快结束了,也就是说一个季度就结束了:而我也因为年前笔记本坏了,今天刚修好了,那么也应该继续学习和博客之旅了.今年的博客之旅,从JVM开始学起,下面我们就言归正传,进入正题. 一.J ...

  2. (转) JVM——Java类加载机制总结

    背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂. 转载:http://blog.csdn.net/seu_calvin/article/details/52301541 1. ...

  3. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  4. JVM内存结构 JVM的类加载机制

    JVM内存结构: 1.java虚拟机栈:存放的是对象的引用(指针)和局部变量 2.程序计数器:每个线程都有一个程序计数器,跟踪代码运行到哪个位置了 3.堆:对象.数组 4.方法区:字节流(字节码文件) ...

  5. JVM之类加载机制

    JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这 ...

  6. JVM——自定义类加载器

    )以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...

  7. 深入理解JVM的类加载

    前言: 前面又说到Java程序实际上是将.class文件放入JVM中运行.虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换,解析和初始化,最终形成可以被虚拟机直接使用的Java类 ...

  8. JVM的类加载机制全面解析

    什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...

  9. JVM的类加载过程以及双亲委派模型详解

    JVM的类加载过程以及双亲委派模型详解 这篇文章主要介绍了JVM的类加载过程以及双亲委派模型详解,类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象 ...

随机推荐

  1. mongoDb造数据

    package mongoUtil; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import ...

  2. web安全系列3:http拦截

    这是web安全系列第三篇,我们讲讲HTTP请求的拦截.关于http的内容请翻看我的上一篇文章. 首先,我们开始需要一个安装好的java环境,64位的.请自行安装和配置环境变量,如果遇到问题可以留言评论 ...

  3. netcore程序部署及守护

    一.程序发布 1.在本机编译无误的情况下,选择发布成文件系统.注意如果使用了swagger 需要将生成的xml文档说明复制到发版包里面.否则会报错.(可以在项目的csproj 中加入 <Prop ...

  4. SpringBoot_配置文件

    Properties配置 SpringBoot中采用了大量的自动化配置,但是对开发者而言,在实际项目中不可避免会有一些需要自己手动配置,承载这些自定义配置的文件就是resources 目录下的appl ...

  5. 阿里云远程连接CentOS

    1.购买一个CentOS的ECS服务器: 2.修改安全组,开放SSH/22的端口号: 这里是22/22为SSH连接的端口号:3389为远程桌面的默认端口号 3.利用xshell或者SecureCRT连 ...

  6. DOS命令 学习笔记

    将遇到的一些DOS命令(linux命令和DOS命令都存在的命令也记录在此处)记录下,方便以后查询 DOS命令计算文件md5/sha1/sha256 certutil -hashfile yourfil ...

  7. MySQL数据库(三)索引总结

    一.什么是索引?  索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存. 如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录 ...

  8. 使用tcpdump探测TCP/IP三次握手

    读计算机应该就同说过TCP/IP三次握手,但是都没有去验证过,今天心血来潮,去验证了一下,于是乎写下了这篇博客,可能写的可能有问题,还请多多指教 包括我学习,还有从很多资料来看资料,第三次握手,应该会 ...

  9. 初识大数据(三. Hadoop与MPP数据仓库)

    MPP代表大规模并行处理,这是网格计算中所有单独节点参与协调计算的方法. 是将任务并行的分散到多个服务器和节点上,在每个节点上计算完成后,将各自部分的结果汇总在一起得到最终的结果. MPP DBMS是 ...

  10. python学习笔记-调用接口

    requests模块 1.get请求: url = 'http://api.nnzhp.cn/api/user/stu_info' data = {'stu_name':'小黑'} #请求数据 req ...