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

类加载的规则:

全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入

父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类

缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。

类加载的过程:

包括加载、链接(含验证、准备、解析)、初始化

如下图所示:

1、加载:

  类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,作为方法区这个类的数据访问的入口

也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。具体包括以下三个部分:

(1)通过类的全名产生对应类的二进制数据流。(根据early load原理,如果没找到对应的类文件,只有在类实际使用时才会抛出错误)

(2)分析并将这些二进制数据流转换为方法区方法区特定的数据结构

(3)创建对应类的java.lang.Class对象,作为方法区的入口(有了对应的Class对象,并不意味着这个类已经完成了加载链接)

通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源:

(1)从本地文件系统加载class文件,这是绝大部分程序的加载方式

(2)从jar包中加载class文件,这种方式也很常见,例如jdbc编程时用到的数据库驱动类就是放在jar包中,jvm可以从jar文件中直接加载该class文件

(3)通过网络加载class文件

(4)把一个Java源文件动态编译、并执行加载

2、链接:

链接指的是将Java类的二进制文件合并到jvm的运行状态之中的过程。在链接之前,这个类必须被成功加载。

类的链接包括验证、准备、解析这三步。具体描述如下:

2.1  验证:

验证是用来确保Java类的二进制表示在结构上是否完全正确(如文件格式、语法语义等)。如果验证过程出错的话,会抛出java.lang.VertifyError错误。

主要验证以下内容:

  • 文件格式验证

    • 验证字节流是否符合class文件格式的规范,并且能被当前虚拟机处理,如是否以魔数0xCAFEBABE开头、主次版本号是否在当前虚拟机处理范围内、常量池是否有不支持的常量类型等。只有经过格式验证的字节流,才会存储到方法区的数据结构,剩余3个验证都基于方法区的数据进行。
  • 元数据验证
    • 对字节码描述的数据进行语义分析,以保证符合Java语言规范,如是否继承了final修饰的类、是否实现了父类的抽象方法、是否覆盖了父类的final方法或final字段等。
  • 字节码验证
    • 对类的方法体进行分析,确保在方法运行时不会有危害虚拟机的事件发生,如保证操作数栈的数据类型和指令代码序列的匹配、保证跳转指令的正确性、保证类型转换的有效性等。
  • 符号引用验证
    • 为了确保后续的解析动作能够正常执行,对符号引用进行验证,如通过字符串描述的全限定名是都能找到对应的类、在指定类中是否存在符合方法的字段描述符等。

2.2  准备:

  准备过程则是创建Java类中的静态域(static修饰的内容),并将这些域的值设置为默认值,同时在方法区中分配内存空间。准备过程并不会执行代码。

注意这里是做默认初始化,不是做显式初始化。例如:

public static int value = 12;

上面的代码中,在准备阶段,会给value的值设置为0(默认初始化)。在后面的初始化阶段才会给value的值设置为12(显式初始化)。

但是有个特殊情况:

public static final int value = 12;

在编译阶段会为value生成ConstantValue属性,在准备阶段虚拟机会根据ConstantValue属性将value赋值为100。

2.3  解析:

  解析的过程就是确保这些被引用的类能被正确的找到(将符号引用替换为直接引用)。解析的过程可能会导致其它的Java类被加载。

  符号引用和直接引用有什么不同?

  1、符号引用使用一组符号来描述所引用的目标,可以是任何形式的字面常量,定义在Class文件格式中。

  2、直接引用可以是直接指向目标的指针、相对偏移量或则能间接定位到目标的句柄。

3、初始化:

  初始化阶段是类加载过程的最后一步。到了初始化阶段,才真正执行类中定义的Java程序代码(或者说是字节码)。

  初始化阶段是执行类构造器<clinit>方法的过程,<clinit>方法由类变量的赋值动作和静态语句块按照在源文件出现的顺序合并而成,该合并操作由编译器完成。

    1、<clinit>方法对于类或接口不是必须的,如果一个类中没有静态代码块,也没有静态变量的赋值操作,那么编译器不会生成<clinit>;

    2、<clinit>方法与实例构造器不同,不需要显式的调用父类的<clinit>方法,虚拟机会保证父类的<clinit>优先执行;

    3、为了防止多次执行<clinit>,虚拟机会确保<clinit>方法在多线程环境下被正确的加锁同步执行,如果有多个线程同时初始化一个类,

      那么只有一个线程能够执行<clinit>方法,其它线程进行阻塞等待,直到<clinit>执行完成。

    4、注意:执行接口的<clinit>方法不需要先执行父接口的<clinit>,只有使用父接口中定义的变量时,才会执行。

  在以下几种情况中,会执行初始化过程:

(1)创建类的实例

(2)访问类或接口的静态变量(特例:如果是用static final修饰的常量,那就不会对类进行显式初始化。static final 修改的变量则会做显式初始化

(3)调用类的静态方法

(4)反射(Class.forName(packagename.className))

(5)初始化类的子类。注:子类初始化问题:满足主动调用,即父类访问子类中的静态变量、方法,子类才会初始化;否则仅父类初始化。

(6)java虚拟机启动时被标明为启动类的类

  

类的初始化过程(重要)

Student s = new Student();在内存中做了哪些事情?

  • 加载Student.class文件进内存
  • 栈内存为s开辟空间
  • 堆内存为学生对象开辟空间
  • 对学生对象的成员变量进行默认初始化
  • 对学生对象的成员变量进行显示初始化
  • 通过构造方法对学生对象的成员变量赋值
  • 学生对象初始化完毕,把对象地址赋值给s变量

初始化顺序问题

public class TestInstance {

    public static TestInstance instance = new TestInstance();  //初始化 a=1,b=1
public static int a;
public static int b = 0; //a=1,b=0 public TestInstance() {
a++;
b++;
} public static void main(String[] args) {
System.out.println(TestInstance.a);
System.out.println(TestInstance.b);
}
}

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

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

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

  2. JVM之类加载机制

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

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

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

  4. 大白话谈JVM的类加载机制

    前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才 ...

  5. 一文教你读懂JVM的类加载机制

    Java运行程序又被称为WORA(Write Once Run Anywhere,在任何地方运行只需写入一次),意味着我们程序员小哥哥可以在任何一个系统上开发Java程序,但是却可以在所有系统上畅通运 ...

  6. 【JVM】类加载机制

    原文:[深入Java虚拟机]之四:类加载机制 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 类加 ...

  7. 深入理解JVM(3)——类加载机制

    1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...

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

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

  9. JVM虚拟机—JVM的类加载机制

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

随机推荐

  1. matlab怎么定义一个数组

    A=[];n=input('n=');%数组的长度for i=1:n fprintf('a%.0f=',i); x=input('');%分别输入各个数的值 A=[A,x];endA就可以得到长度为n ...

  2. Card(bestcoder #26 B)

    Card Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  3. Linux 中的 wheel 组和 staff 组

    wheel 组的概念 wheel 组的概念继承自 UNIX.当服务器需要进行一些日常系统管理员无法执行的高级维护时,往往就要用到 root 权限:而“wheel” 组就是一个包含这些特殊权限的用户池: ...

  4. PHP 上传文件和读取文件崎岖路

    今天php上传文件和读取文件没有搞出来,全靠后来大神来帮忙,总结一下:主要涉及到一下几个方面,在ubuntu下mkdir文件夹的时候要注意权限问题,一般情况下php是以一个较低的权限去执行的,所以如果 ...

  5. dex和odex相互转换

    一.dex和odex dex是安卓dalvik虚拟机的可执行文件,可以在导出的apk文件里用解压缩软件直接打开.odex是经过优化过的dex.odex一种是从apk程序中提取出来的,与apk文件存放在 ...

  6. 纯Java获得本地MAC地址

    import java.net.*; public class Ipconfig{      public static void main(String[] arguments) throws Ex ...

  7. HDU 4435 charge-station bfs图论问题

    E - charge-station Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u ...

  8. 原创:分享asp.net伪静态成目录形式iis如何设置

    服务器租用详解asp.net伪静态成目录形式iis如何设置: 一.首先介绍一下asp.net伪静态成html后缀iis如何设置的 iis6 伪静态 iis配置方法 图解 1.右键点击 要设置网站的网站 ...

  9. 【SpringMVC】SpringMVC系列13之关于 mvc:annotation-driven

    13.关于 mvc:annotation-driven 13.1.概述      会自动注册RequestMappingHandlerMapping.RequestMappingHandlerAdap ...

  10. Linux运维

    概要:http://os.51cto.com/art/201312/423616.htm 论坛: http://www.linux360.cn/ https://www.centos.bz/ http ...