java虚拟机类加载
java虚拟机中类的加载

(JVM的大致结构图)
从发class文件到内存中的类,按先后顺序,需要经过加载,链接以及初始化三大步骤。
java语言的类型可分为两大类:基本类型(primitive type)和引用类型(references type)
基本类型:是由java虚拟机预先定义好的。
引用类型:Java将其细分为四种,类、接口、数组类和泛型参数。
由于泛型参数会在编译过程中被擦除(泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。),因此Java虚拟机实际上只有前三种。在类、接口和数组类中,数组类是由java虚拟机直接生成的,其他两种则有对应的字节流。
字节流:最常见的形式要属由Java编译器生成的class文件。除此之外,我们也可以在程序内部直接生成,或者从网络中获取字节流。这些不同形式的字节流,都会被加载到java虚拟机中,称为类或者接口。
无论是直接生成的数组类,还是加载的类,java虚拟机都要对其进行链接和初始化。
加载
加载是指查找字节流,并且据此创建类的过程。对于类来说,java虚拟机需要借助类加载器来完成查找字节流的过程。
当JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构:
1、启动类加载器(BootstrapClassLoader):是嵌在JVM内核中的加载器,它是由C++实现的,没有对应的java对象,因此在java中只能用null来代替。它主要负责加载JAVA_HOME/lib下的类库,启动类加载器无法被应用程序直接使用。
除了启动类加载器外,其他的类加载器都是java.lang.ClassLoader的子类,因此有对应的java对象。这些类加载器需要先由另一个类加载器,比如说启动了加载器,加载至java虚拟机中,方能执行类加载。
在Java9之前,启动类加载器负责加载最为基础,最为重要的类,比如存放在jre的lib目录下的jar包(以及由虚拟机参数-Xbootclasspath指定的类)。除了启动类加载器之外,另外两个重要的类加载器是扩展类加载起(extension class loader)和应用类加载器(application class loader),均由java核心类库提供。
2、扩展类加载器(extension class loader):其父类是启动类加载器,他负责加载相对次要、但又通用的类,比如存放在jre的lib/ext目录下的jar包中的类(以及由系统变量java.ext.dirs指定的类)。
3、应用类加载器(application class loader):其父类是扩展类加载器,它负责加载用用程序下的类。(这里的应用程序路径,便是指虚拟机参数-cp/-classpath、系统变量CLASSPATH所制定的路径。)默认情况下,应用程序中包含的类是由应用类加载器加载的。
java9引入了模块系统,,并且略微更改了上述的类加载器,扩展类加载器被改名为平台类加载器(platform class loader)。Java SE 中除了少数几个关键模块,比如说、java.base是由启动类加载器加载之类,其他的模块均由平台加载器所加载。
除了java核心类库提供的类加载器之外,我们还可以加入自定义的加载器,来实现特殊的加载方式。举个例子,我们可以对class文件进行加密,加载时再利用自定义的类加载最其解密。
除了加载功能之外,类加载器还提供了命名空间的作用。在java虚拟机中,类的唯一性是由类加载器实例以及类的全名一同确定的。即便是通一串字节流,经由不同的类加载器加载,也会得到两个不同的类。在大型应用中,我们往往会借助这一特性,来运行同一个类的不同版本。
链接
链接是指将创建成的类合并至java虚拟机中,使之能执行的过程。它可以分为验证、准备及解析三个阶段。
验证:确保被加载的类能够满足java虚拟机的约束条件,检验被加载的类是否有正确的内部结构,并和其他类协调一致。
准备:为被加载类的静态字段分配内存,并设置默认初始值。
解析:将类中的二进制数据中的符号引用替换成直接引用(final修改的常量的替换)。
JVM并没有要你在链接过程中完成解析,它仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要完成对这些符号引用的解析。
初始化
在java代码中如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值。
如果直接赋值的静态字段被final修饰,并且他的类型是基本类型或字符串时,那么该字段便会被java编译器标记为常量值(ConstantValue),其初始化直接被java虚拟机完成。除此之外的直接赋值操作以及所有静态代码块中的代码,则会被java编译器置于同一方法中,并把它命名为<clinit>。
类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行<clinit>方法的过程。java虚拟机会通过加锁来确保类的<clinit>方法仅被执行一次。
只有当初始化完成之后,类才正式称为可执行的状态。
JVM初始化一个类分为几步:
1、假如这个类还没有被加载和链接,程序先加载并链接这个类。
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类。
3、假如类中有初始化语句,则依次执行其初始化语句。
类的加载和初始化何时被触发
1、当虚拟机启动时,初始化用户指定的主类。(直接使用java.exe命令来运行某个主类)
2、创建类的实例(new方法)。
3、调用某个类的静态方法,初始化该静态方法所在的类。
4、访问某个类或接口的静态属性,初始化该静态属性所在的类。
5、使用反射机制来创建某个类或接口的对应java.lang.Class对象(Class.forName("Person")),初始化这个类。
6、子类的初始化会触发父类的初始化。
7、如果一个接口定义了default方法,那么直接实现或间接实现该接口的类的初始化,会触发该接口的初始化。
8、当初次使用MehodHandle实例时,初始化该MehodHandle指向的方法所在的类。
注:此文为极客时间郑雨迪专栏,java虚拟机讲解及自己查资料的学习总结。郑雨迪《深入拆解Java虚拟机》很不错。
java虚拟机类加载的更多相关文章
- Java虚拟机类加载机制——案例分析
转载: Java虚拟机类加载机制--案例分析 在<Java虚拟机类加载机制>一文中详细阐述了类加载的过程,并举了几个例子进行了简要分析,在文章的最后留了一个悬念给各位,这里来揭开这个悬 ...
- 深入理解Java虚拟机---类加载机制(简略版)
类加载机制 谈起类加载机制,在这里说个题外话,当初本人在学了两三个月的Java后,只了解了一些皮毛知识,就屁颠屁颠得去附近学校的招聘会去蹭蹭面试经验,和HR聊了一会后开始了技术面试,前抛出了两个简单的 ...
- 面试官,不要再问我“Java虚拟机类加载机制”了
关于Java虚拟机类加载机制往往有两方面的面试题:根据程序判断输出结果和讲讲虚拟机类加载机制的流程.其实这两类题本质上都是考察面试者对Java虚拟机类加载机制的了解. 面试题试水 现在有这样一道判断程 ...
- Java虚拟机类加载器及双亲委派机制
所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...
- [转]Java虚拟机类加载机制
原文地址:http://blog.csdn.net/u013256816/article/details/50829596 看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎 ...
- java虚拟机类加载机制和双亲委派模型
java虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型. 类的生命周期是从类被加载到虚拟机内存中,到卸 ...
- 面试官,不要再问我“Java虚拟机类加载机制”了(转载)
关于Java虚拟机类加载机制往往有两方面的 面试题:根据程序判断输出结果和讲讲虚拟机类加载机制的流程.其实这两类题本质上都是考察面试者对Java虚拟机类加载机制的了解. 面试题试水 现在有这样一道判断 ...
- JVM(三)-java虚拟机类加载机制
概述: 上一篇文章,介绍了java虚拟机的运行时区域,Java虚拟机根据不同的分工,把内存划分为各个不同的区域.在java程序中,最小的运行单元一般都是创建一个对象,然后调用对象的某个 方法.通过上一 ...
- 【转载】Java虚拟机类加载机制与案例分析
出处:https://blog.csdn.net/u013256816/article/details/50829596 https://blog.csdn.net/u013256816/articl ...
- Java虚拟机类加载机制
看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的.随着编程经验的日积月累,越来越感觉到了解虚拟机相关要领的重要性.闲话不多说,老规矩 ...
随机推荐
- 兼容ie8的框架
layui Flow-UI http://refined-x.com/Flow-UI/
- bzoj 3307 雨天的尾巴
题目链接:传送门 题目大意:中文题,略 题目思路:网上有题解说是合并线段树的,但是太难蒟蒻不会,只能用树剖求解 如果不是树而是一维数组我们会怎么解? 当然是利用前缀和思想标记 (L) v+1,(R+1 ...
- iOS 根据经纬度计算与地理北极夹角
http://www.aiuxian.com/article/p-2767848.html #define toDeg(X) (X*180.0/M_PI) /** * @method 根据两点经纬度 ...
- pycharm 和 Anaconda 下的 opencv 安装
学习真的切忌三天打鱼两天晒网!! 一开始python下的opencv已经都弄好了,中间电脑坏了一次,好久没有接触这个,就全部都忘完了.深感惋惜. 今天又从新安装了一下opencv.在anaconda下 ...
- Redis分布式队列解决文件并发的问题
1.首先将捕获的异常写到Redis的队列中 public class MyExceptionAttribute : HandleErrorAttribute { public static IRedi ...
- SQL Server 存储过程生成流水号
SQL Server利用存储过程生成流水号 USE BiddingConfig SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON GO -- =========== ...
- JS生成GUID方法
function GUID() { this.date = new Date(); /* 判断是否初始化过,如果初始化过以下代码,则以下代码将不再执行,实际中只执行一次 */ if (typeof t ...
- Lodash 常用API中文参考
lodash和underscore都是现在非常流行的两个javascript库,提供了一套函数式编程的实用功能. 而lodash本身最初也是underscore的一个fork,因为和其他(Unders ...
- pandas的merge方法
数据合并时可以使用merge方法,对两个dataFrame根据某一个series合并,这个方法非常好用,只要找到了合并的标准,新的数据就可以重构出来. 1.命令: pd.merge() on:列名,j ...
- numpy基本方法总结 --good
https://www.cnblogs.com/xinchrome/p/5043480.html 一.数组方法 创建数组:arange()创建一维数组:array()创建一维或多维数组,其参数是类似于 ...