7.1JVM类加载机制

  虚拟机把数据从Class文件加载到内存,并且校验、转换解析和初始化最终形成可以被虚拟机使用的Java类型,这就是虚拟机的类加载机制。

7.2类加载的时机

  1.类加载的步骤开始的顺序: 加载(Loading) -> 验证(Verification) -> 准备(Preparation) -> 解析(Resolution) -> 初始化(Initialization) -> 使用(Using) -> 卸载(Unloading) ,验证、准备、解析的过程称为 链接 ,而加载、验证、准备、初始化和卸载的执行的开始顺序是确定的,而解析可能在初始化之后开始;

  2.关于初始化阶段,有5种情况需要立即进行初始化:

    (1)遇到这四个字节码指令时:new、getstatic、putstatic、invokestatic,如果类未进行过初始化,那么进行初始化,这几个字节码指令所在场景:new对象、调用类的静态属性、调用类的静态方法;

    (2)使用 java.lang.reflect 包的方法对类进行反射调用时,如果未进行过初始化,那么进行初始化;

    (3)当初始化一个类时,其父类未进行初始化时,对其父类进行初始化;

    (4)虚拟机启动时需要初始化一个指定的主类(包含main()方法的类);

    (5)使用jdk1.7, java.lang.invoke.MethodHandle 实例的解析结果为 REF_getStatic 、 REF_putStatic 、 REF_invokeStatic 的方法句柄,如果此句柄对应的类未初始化,那么进行初始化。

  3.只有以上五种情况类才会被初始化,它们也叫 主动引用 ,而其他的引用类的方式则不会初始化类,它们叫做 被动引用 :

    (1)使用子类访问父类的静态属性时,不会初始化子类;

    (2)创建一个类的数组时,不会初始化此类,但是会初始化出一个另外的类,代表这个数组对象;

    (3)访问一个类的静态常量时,不会初始化这个类,这个静态常量进入常量池会被归属给NonInitialization类的常量池中,代表不会初始化;

7.3类加载的过程

  1.加载:

    (1)通过类的全限定名来获取Class文件的二进制流;

    (2)将这个字节流根据虚拟机所需要的存储结构存放在内存中;

    (3)生成这个类的 java.lang.Class 对象,作为访问类的数据的外部接口;

  2.验证:

    虽然Java代码的编译过程不允许一些不安全的做法(C/C++常做),比如:访问数组边界以外的数据、错误的对象转型、跳转到不存在的行,但是不能保证Class文件不被修改,所以验证这一步骤作为连接的第一个阶段对于JVM的安全性来说非常重要;

    验证的过程又分为四个阶段: 文件格式验证 、 元数据验证 、 字节码验证 、 符号引用验证

    (1)文件格式验证:①验证魔数;②主、次版本号;③长度检查;等等

    (2)元数据验证:①验证除 java.lang.Object 类以外其他类有无继承父类;②是否继承了final类;③非抽象类是否重写了必须重写的方法;④字段、方法和父类是否矛盾;等等

    (3)字节码验证:①验证错误的对象转型;②跳转到不存在的行;等等

    (4)符号引用验证:①验证能不能通过符号引用的类的全限定名找到这个类;②验证这个符号引用的类、字段和方法的可访问性(public、private);等等,验证完成之后,则符号引用转化为 直接引用 (内存地址引用);

  3.准备:

     准备阶段是为类变量(static修饰)分配内存并赋予初始值的阶段;

    (1)这里说的赋予初始值说的一般都是零值,比如: ; 这里的 i 在准备阶段完成之后会被赋值为0而非1,赋值为1那是初始化阶段;

    (2) ; 而这里的 i在准备阶段之后赋值为1;

  4.解析:

    将常量池内的 符号引用 转换为 直接引用 的过程,分为 类或接口解析 、 字段解析 、 类方法解析 、 接口方法解析 。

  5.初始化:

    初始化阶段才算是真正开始运行Java代码,初始化阶段就是运行类构造器的 <cinit>() 方法,对应 static{} 方法块;

    (1)<cinit>()方法只能访问到static{}代码块前面的变量,而在static后面的变量,只能赋值,不能访问引用(非法向前引用);

    (2)子类初始化,会默认先初始化父类来调用父类的<cinit>()方法;

    (3)一般类中没有static{}代码块,那么也就不会生成<cinit>()方法;

    (4)接口不能写static{}代码块,但是赋值给变量时也会生成<cinit>()方法;

    (5)<cinit>()方法是同步的,线程安全的。

7.4类加载器

   类加载器 作用于 加载 阶段中,根据类的全限定名来获取Class文件的二进制流。

  1.关于类和类加载器:

    两个类要相等( equals() ),它们首先要是同一个类加载器进行加载的;

  2.双亲委派模型:

    (1)三种系统的类加载器:

      ①启动类加载器(Bootstrap ClassLoader):加载 %JAVA_HOME%/lib 下和 -Xbootclasspath 指定的目录下的类库;

      ②扩展类加载器(Extension ClassLoader):加载 %JAVA_HOME%/lib/ext 目录下和 java.ext.dirs 系统变量所指定的目录下的类库;

      ③ 应用程序类加载器(Application ClassLoader):加载用户类路径下的类库;

    (2)双亲委派模型:

      如下图所示,要求除 启动类加载器(Bootstrap ClassLoader) 以外,其它类加载器都要有自己的父加载器,它们之间不是 继承 关系,而是 组合 复用的关系;

      

    (3)双亲委派机制工作过程:

      一个类加载器在收到类加载的请求时,不会立即去加载这个类,而是向 父类加载器 请求加载,依次类推,直到顶层类加载器,只有当类加载器不能加载此类时才会让 子类加载器 去加载这个类;

    (4)双亲委派机制的意义:

      如此保证了类不会因为不同类加载器导致加载出不同的类,从而使程序混乱,例如自己写一个 java.lang.String 类,系统只加载了jdk默认的 java.lang.String 的类文件,而不会加载自己写的java.lang.String类;

  3.破坏双亲委派模型:

深入理解JVM(七)JVM类加载机制的更多相关文章

  1. 深入理解和探究Java类加载机制

    深入理解和探究Java类加载机制---- 1.java.lang.ClassLoader类介绍 java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字 ...

  2. JVM(七):JVM内存结构

    JVM(七):JVM内存结构 在前几节的文章我们多次讲到 Class 对象需要分配入 JVM 内存,并在 JVM 内存中执行 Java 代码,完成对象内存的分配.执行.回收等操作,因此,如今让我们来走 ...

  3. 深入理解JVM,虚拟机类加载机制

    类加载过程概览 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括以下7个阶段: 加载(Loading) 验证(Verification) 准备(Preparation) 解析(Re ...

  4. 【JVM】JVM系列之类加载机制(四)

    一.前言 前面分析了class文件具体含义,接着需要将class文件加载到虚拟机中,这个过程是怎样的呢,下面,我们来仔细分析. 二.什么是类加载机制 把class文件加载到内存,并对数据进行校验.转换 ...

  5. 图解JVM和Tomcat类加载机制

    说到本篇的tomcat类加载机制,不得不说翻译学习tomcat的初衷. 之前实习的时候学习javaMelody的源码,但是它是一个Maven的项目,与我们自己的web项目整合后无法直接断点调试.后来同 ...

  6. 【JVM】虚拟机类加载机制

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

  7. JVM之Java类加载机制

    什么是类加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这既是虚拟机的类加载机制 类的生命周期 生命周期简述 ...

  8. JVM之虚拟机类加载机制

    有兴趣可以先参考前面的几篇JVM总结: JVM自动内存管理机制-Java内存区域(上) JVM自动内存管理机制-Java内存区域(下)     JVM垃圾收集器与内存分配策略(一) 我们知道,在编写一 ...

  9. Java面试题:JVM中的类加载机制

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

随机推荐

  1. LeetCode 144. Binary Tree Preorder Traversal 二叉树的前序遍历 C++

    Given a binary tree, return the preorder traversal of its nodes' values. Example: Input: [,,] \ / Ou ...

  2. Java Native调用C方法

    1.通过JNI生成C调用的头文件:Java源码: import java.io.File; public class Test { static { System.load("D:" ...

  3. FPGA——流水灯(一)

    对于FPGA的结构原理,先不进行全面的了解,先能根据教程程序看得懂,写得出来跑起来.慢慢的了解程序运行的原理,各种语法的使用. 今天对流水的程序有一个认识,熟悉软件的使用,语法规则,原理.以正点原子的 ...

  4. JS常见兼容性问题

    兼容性问题:函数(方法)兼容 描述:部分W3C指定的函数,有部分老的浏览器不支持 解决: 条件判断,如果有,则使用,添加原型方法,例如 String 的 trim 方法 if(!String.prot ...

  5. FutureTask原理解析

    原文链接:http://www.studyshare.cn/blog-front/blog/details/1130 首先写一个简单的Demo public static void main(Stri ...

  6. js中this的绑定规则及优先级

    一.   this绑定规则 函数调用位置决定了this的绑定对象,必须找到正确的调用位置判断需要应用下面四条规则中的哪一条. 1.1 默认绑定 看下面代码: function foo() { cons ...

  7. Unity3D人脸建模 AvataSDK研究

    1.Unity与windows交互 调用文件浏览器 1.用C#调用comdlg32.dll  ,  利用GetOpenFileName实现打开文件对话框 <1> 整体参考https://w ...

  8. 微信小程序-if条件渲染

    #index.wxml <view>今天吃啥</view> <view wx:if="{{condition==1}}"> 饺子 </vi ...

  9. 【笔记】Python基础六:模块module介绍及常用模块

    一,module模块和包的介绍 1,在Python中,一个.py文件就称之为一个模块(Module). 2,使用模块的好处? 最大的好处是大大提高了代码的可维护性 其次,编写代码不必从零开始,我们编写 ...

  10. js事件不能触发

    在span标签添加了个onclick事件,捣腾了半天触发不了,设置z-index:1000也没用. 最后发现是元素没设置宽度width导致的,压根儿没往这方面想. 因为添加onclick的span标签 ...