我们在编写Java程序之后,会通过编译器得到一个class文件,这个class文件是如何与JVM进行配合的呢?类中的信息是如何变成JVM可以使用的Java类型呢?这些都是类加载机制做到的。

虚拟机把描述类的数据从class文件中加载到内存里,并对数据进行校验,转换解析和初始化,最终形成被虚拟机直接使用的Java类型,这就是类加载机制。

类的生命周期

一个类从加载进入内存到卸载出内存,一共经过以下几个生命周期。

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化
  6. 使用
  7. 卸载

这篇文章主要说明前5个生命周期,也就是说主要总结类从加载到使用的过程。

类的加载的过程

类的第一个生命周期是加载,那么类是什么时候执行加载过程的呢?这个过程JVM规范并没有明确说明,但是针对类的初始化,JVM给出了硬性的规定,只有以下五种情况才会进行类的初始化。

  • 遇到new,getStaic,putStatic,invokestatic这四个字节码指令时,这四个字节码对应的Java代码场景是:使用new关键字实例化对象,读取或设置一个类的静态属性的时候(该属性被final修饰除外),调用一个类的静态方法的时候。
  • 使用反射对类进行调用的时候
  • 当初始化一个类,而他父类还没有初始化的时候,则需要先初始化他的父类
  • main函数所在的那个类。
  • JDK7中一个methodHandle实例最后的解析结果为REF_getStatic,REF_putStatic,REF_invokeStatic,该方法对对应的类还没有初始化的时候,就会触发其初始化。该方法详见博客

上述说明了类初始化的时机,那么类的加载自然要在初始化之前。这也说明了在运行时才会执行类的初始化。
那么加载的这个过程,JVM做了什么工作呢?在加载阶段,JVM主要完成3件事情

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

我们先说第一步,通过一个类的全限定名来获取此类的二进制字节流。这个说法实际上是很大的一个操作的空间,这也是各种Java技术能够实现的基础。比如,我们可以通过zip包中获取,那么就有了后来的jar,war,我们还可以通过网络中获取这个类,这就是applet,甚至动态代理,运行时在生成特定的class二进制流,或者由其他文件生成,比如JSP,由JSP文件生成对应的Class文件。

那么,为什么这一步会出现这么多种类繁多的加载技术呢,是因为通过一个类的全限定名来获取定义此类的二进制字节流这一动作是放到了Java虚拟机外部去实现的,是为了方便让应用自己去决定如何获取所需要的类。实现这个动作的功能是常说的类加载器。

类加载器的功能就是将获取class文件,并将其转换为class对象。因为class对象是由类加载器得到的,所以如果比较两个类是否相等,也必须在同一个类加载器加载的前提下,这里的相等时包括class对象的equals,instanceOf等作出的判断。

那么,针对JDK中这么多的类,以及还有我们自己编写的类,是否都是用同一个类加载器加载的呢?这显然不是,我们从Java开发者角度来看看究竟有哪些类加载器,他们是怎么配合的。

  • 启动类加载器
  • 扩展类加载器
  • 应用程序类加载器

启动类加载器是加载%JAVA_HOME/lib目录中的类,虚拟机按照名字来识别,比如rt.jar,不是虚拟机认可的名字,即使放在下面也没有用。该加载器是JVM自身的一部分。

扩展类加载器是负责加载$JAVA_HOME/lib/ext目录下的类。该加载器继承自ClassLoader。

应用程序加载器或者叫做系统类加载器,负责加载ClassPath上指定的类,如果应用程序没有自定义过自己的类加载器,一般情况这个就是程序默认的类加载器。

这三种加载器是相互配合使用,配合的方式是双委派模型,如下图所示:

双亲委派模型的工作过程如下:
如果一个类加载器收到了类加载的过程,他首先不会自己去尝试加载这个类,而是把这个类委派给自己的父类加载器去完成,每一个层次的加载器都是如此,因为所有的类的加载请求都会最终传到顶层的启动类加载器中,只有父类的加载器无法完成这个加载请求时,子加载器才会去尝试自己的加载。
这样做的做的目的在于,保持类在整个JVM中唯一性,上面我们说过了,只有同一个类加载器加载出的类才是相等,如果我们编写了一个Object类,而不采用双亲委派模型的形式去加载,那么会加载出很多不同的Object类。

至此,类的加载阶段就介绍完毕,告一段落了。

类的链接阶段

类的链接阶段主要包含验证,准备,解析这三个阶段,本文简要说明这个三个阶段做的事情。

  • 验证阶段是验证加载类的信息是否会危害虚拟机
  • 准备阶段是正式将类变量分配内存并设置类初始值的阶段,这些都是在方法区进行分配
  • 解析阶段是将常量池的符号引用替换为直接引用的过程

类的初始阶段

类的初始化阶段才会真正执行Java代码中那些语句。

初始化阶段是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收藏类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生
当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步

理解JVM——类加载机制的更多相关文章

  1. 深入理解JVM虚拟机6:深入理解JVM类加载机制

    深入理解JVM类加载机制 简述:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 下面我们具体 ...

  2. 深入理解JVM类加载机制

    1.什么是类加载机制? JVM把class文件加载到内存里面,并对数据进行验证.准备.解析和初始化,最终能够被形成被JVM可以直接使用的Java类型的过程. 生命周期包含:加载,验证,准备,解析,初始 ...

  3. 深入理解JVM类加载机制 classloader

    转自https://www.cnblogs.com/ygj0930/p/6536048.html

  4. 理解Java类加载机制(译文)

    理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...

  5. JVM基础系列第7讲:JVM 类加载机制

    当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析.运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制.JVM 虚拟机执行 class 字节 ...

  6. Java虚拟机(四):JVM类加载机制

    1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...

  7. JVM类加载机制(转)

    原文出自:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运 ...

  8. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  9. 一夜搞懂 | JVM 类加载机制

    前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习类加载机制? 今天想跟大家唠嗑唠嗑Java的类加载机制,这是Java的一个很重要的创 ...

随机推荐

  1. SqlServer知识点

    在公司天天写Sql写,存储过程,但是公司工具模板把创建的语句都写好了,只负责写里面的逻辑,久而久之,创建语句都不会写了.还有一些知识点都很模糊,平常使用的时候都不清楚,稀里糊涂的就在用.在这里整理一下 ...

  2. 【转】手机web前端调试页面的几种方式

    前言 PC端web页面调试比较容易,这里主要说几种移动端调试的方法,从简单到复杂.从模拟调试到远程调试,大概分为几部分: 1.Chrome DevTools(谷歌浏览器)的模拟手机调试 2.weinr ...

  3. Winform无边框窗体拖动

    调用示例 当然,BUG还是有的,不过基本需求倒也可以

  4. 三:Jquery-event

    一:jq中事件 1.页面载入事件 ready()方法 格式: $(document).ready(function(){}); $(function(){}); 2.绑定事件 click(),dblc ...

  5. ASP.NET MVC控制器里捕获视图的错误验证信息(ErrorMessage)

    ViewModel类: /// <summary> /// 评论用验证视图 /// </summary> public partial class VCreateShopCom ...

  6. 【转】关于JTA,XA,ACID

    对于我们这种初学者,可能会使用spring带给我们的@Transactional,可能了解JTA,可能会使用jotm.atomikos,又会遇到一些名词XA,支持XA的数据库驱动等等诸多问题,然后就会 ...

  7. scala 编程思想—学习笔记

    方法 方法是打包在某个名字下的小程序.在使用方法时,也就是调用方法时就会执行 这个小程序.方法将一组活动组合起来并赋予一个名字,这就是组织程序的最基本方式. scala 中方法的基本形式为 def m ...

  8. 使用sshkey连接github等服务器

    平常使用git时因为用了https的方式,所以经常要输入密码,其实我们是可以通过这个公钥连接github git.oschina.net等服务器,这样可以省去了我们输入用户名密码这么一个步骤了. 1. ...

  9. jQuery基础(动画篇 animate,显示隐藏,淡入淡出,下拉切换)

    1.jQuery中隐藏元素的hide方法   让页面上的元素不可见,一般可以通过设置css的display为none属性.但是通过css直接修改是静态的布局,如果在代码执行的时候,一般是通过js控制元 ...

  10. Android Dialog的整个生命周期

    Activities提供了一种方便管理的创建.保存.回复的对话框机制,例如 onCreateDialog(int), onPrepareDialog(int, Dialog), showDialog( ...