JVM学习记录-类加载时机
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是类的加载机制。
在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的。类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:
加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中哦验证、准备、解析3个部分统称为连接(Linking),这7个阶段顺序如下图:
其中加载、验证、准备、初始化、和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始(这里仅仅指的是开始,而不是按部就班的进行或完成,是因为这些阶段通常都是相互交叉的进行的,通常在一个阶段执行的过程中调用、激活另外一个阶段),而解析阶段则不一定,它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定。
那么在什么时候开始类加载过程的第一个阶段(也就是加载)呢?Java虚拟机规范中并没有进行强制约束,这点虚拟机根据自身实现来把握。但对于初始化阶段,虚拟机规范则是严格规定了有且只有5中情况必须立即对类进行初始化(加载,验证,准备肯定要在此之前进行了)。
- 创建类实例的时候,读取或者设置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的除外),以及调用一个类的静态方法的时候。
- 对类进行反射调用的时候,如果没有进行过初始化则需要先出发其初始化过程。
- 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先出发其父类的初始化过程。
- 当虚拟机启动时,定义了入口(含有main()方法的那个类)的主类,虚拟机会先初始化这个主类。
- 当使用JDK1.7及以上的版本中的动态语言支持时,若一个java.lang.invoke.MethodHandle实例最后的解析结果是:REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先出发它的初始化过程。
虚拟机规范中指出有且只有这5种场景会出发初始化,并且这5种场景的行为称为对一个类的“主动引用”,除此之外所有引用类的方式都不会触发初始化,不触发初始化的也被称为被动引用。
用代码例子来说明被动引用。
- /**
- * 通过子类引用父类的的静态字段,不会导致子类初始化
- */
- public class SuperClass {
- static {
- System.out.println("SuperClass init!");
- }
- public static int value = 888;
- public static final String JVM_TEST = "JVM TEST";
- }
- /**
- * 子类
- */
- public class SubClass extends SuperClass {
- static {
- System.out.println("SubClass init!");
- }
- }
- /**
- * 测试
- */
- public class Test {
- public static void main(String[] args){
- System.out.println(SubClass.value);
- }
- }
打印结果为:
SuperClass init!
888
对于静态字段,只有定义这个字段的类才会被初始化,因此通过子类调用其父类中定义的静态字段,只会出发父类的初始化。
- /**
- * 通过数组定义引用类,不会出发类的初始化
- */
- public class Test {
- public static void main(String[] args){
- SuperClass[] supers = new SuperClass[12];
- }
- }
运行结果并没有打印出“SuperClass init!”,这说明并没有对SuperClass进行初始化,定义数组不会触发类的初始化。
- /**
- * 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类中,因此不会出发定义常量的类的初始化。
- */
- public class Test {
- public static void main(String[] args){
- System.out.println(SuperClass.JVM_TEST);
- }
- }
运行结果也没有打印出“SuperClass init!”,因为虽然引用了SuperClass的常量,但其实在编译极端通过常量传播优化,已经将此常量存储到了Test类的常量池中,因Test类对此常量的引用,都会转化为Test类对自身常量池的引用了。这说明SuperClass和Test这两个类,在编译阶段完成后就没有任何关系了。
接口的加载过程和类的加载过程步骤上是一致的,但是稍有不同的是上面的例子都是用静态语句块“static{}”来输出初始化信息的,在接口中不能使用“static{}”静态语句块。还有一个不同是:当一个类在初始化的时候,要求其父类全部都已经初始化过了,但是一个接口在初始化的时候,不要求其父接口都初始化过,只有真正使用到父接口的时候(例如:引用父接口中定义的常量)才会初始化。
JVM学习记录-类加载时机的更多相关文章
- JVM学习记录-类加载的过程
类的整个生命周期的7个阶段是:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(Initialization).使用(Us ...
- JVM学习记录-类加载器
前言 JVM设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外面去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类 ...
- JVM学习笔记——类加载和字节码技术篇
JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...
- Java虚拟机JVM学习05 类加载器的父委托机制
Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...
- JVM学习笔记——类加载过程
JVM学习笔记——类加载过程 类加载模型——双亲委派模型(Parents Delegation Model)也可称为“溯源委派加载模型” Java的类加载器是一个运行时核心基础设施模块,主要是启动之初 ...
- JVM学习记录-线程安全与锁优化(二)
前言 高效并发是程序员们写代码时一直所追求的,HotSpot虚拟机开发团队也为此付出了很多努力,为了在线程之间更高效地共享数据,以及解决竞争问题,HotSpot开发团队做出了各种锁的优化技术常见的有: ...
- JVM学习之类加载
该文使用Hotspot JDK1.7 一.类加载器 1.什么是类加载器 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java ...
- JVM学习记录
本博客是为了自己学习JVM而建立,只记录一些自己学习的经过. 最近在看<深入理解Java虚拟机>这本书,里面的内容,很是乏味,因为看不懂所以就会觉得很枯燥,觉得很枯燥看着看着就犯困,然后就 ...
- jvm学习记录-对象的创建、对象的内存布局、对象的访问定位
简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以Hot ...
随机推荐
- javax.mail
摘抄 example: public static void sendEmail(ConfBean cBean, String filename, String filepath) { try { P ...
- 解决miner.start() 返回null
下面我列举了三种解决方案,前面两张是某两位大佬试出来的,第三种是我蒙出来的. 第一种解决方案 转载自 http://mp.weixin.qq.com/s/AB9vj1EzOgWT7JyryfQhDg ...
- 学会分析YUV数据
做视频采集与处理,自然少不了要学会分析YUV数据.因为从采集的角度来说,一般的视频采集芯片输出的码流一般都是YUV数据流的形式,而从视频处理(例如H.264.MPEG视频编解码)的角度来说,也是在原始 ...
- Django之代码风格
1 代码风格 稍微关注一下下面这些代码标准风格指导规则将会对你大有益处,我们高度建议你通读词章,即便你此时可能正想跳过它. 1.1 让你的代码保持可读性的重要性 代码在读方面的重要性胜过写.一个代码块 ...
- git添加本地的项目到git远程管理仓库
目标:将本地存在的项目添加到git远程仓库管理 步骤: 1. 需要一个git远程仓库管理地址 例如:https://github.com/xingfupeng/test.git git@github. ...
- Flask类的属性和方法大全
Flask Property__class____dict____doc____module__app_ctx_globals_classconfig_classdebugdefault_config ...
- 使用webpack打包后的vue项目如何运行(express)
我们知道使用webpack打包vue项目后会生成一个dist文件夹,dist文件夹下有html文件和其他css.js以及图片等,那么打包后的文件该如何正确运行呢? 倘若直接打开html文件,会报如下错 ...
- 使用on-my-zsh时,php 输出内容后面多个%号
今天用php写个命令行的小工具时,突然发现在echo输出后,总是会多个%号,开始以为是代码的问题,然后新建了一个代码文件: <?php echo 'hello world'; 输出结果: hel ...
- Java 面试知识点解析(三)——JVM篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- 用nginx缓存静态文件
这篇教程说明你应该怎样配置 nginx.设置 HTTP 头部过期时间,用 Cache-Control 中的 max-age 标记为静态文件(比如图片. CSS 和 Javascript 文件) ...