JVM的类加载时机
类加载过程中每个步骤的顺序
我们已经知道,类加载的过程包括:加载、连接、初始化,连接又分为:验证、准备、解析,所以说类加载一共分为5步:加载、验证、准备、解析、初始化。
其中加载、验证、准备、初始化的开始顺序是依次进行的,这些步骤开始之后的过程可能会有重叠。
而解析过程会发生在初始化过程中。
类加载过程中“初始化”开始的时机
JVM规范中只定义了类加载过程中初始化过程开始的时机,加载、连接过程都应该在初始化之前开始(解析除外),这些过程具体在何时开始,JVM规范并没有定义,不同的虚拟机可以根据具体的需求自定义。
初始化开始的时机:
- 在运行过程中遇到如下字节码指令时,如果类尚未初始化,那就要进行初始化:new、getstatic、putstatic、invokestatic。这四个指令对应的Java代码场景是:
- 通过new创建对象;
- 读取、设置一个类的静态成员变量(不包括final修饰的静态变量);
- 调用一个类的静态成员函数。
- 使用java.lang.reflect进行反射调用的时候,如果类没有初始化,那就需要初始化;
- 当初始化一个类的时候,若其父类尚未初始化,那就先要让其父类初始化,然后再初始化本类;
- 当虚拟机启动时,虚拟机会首先初始化带有main方法的类,即主类;
主动引用 与 被动引用
JVM规范中要求在程序运行过程中,“当且仅当”出现上述4个条件之一的情况才会初始化一个类。如果间接满足上述初始化条件是不会初始化类的。
其中,直接满足上述初始化条件的情况叫做主动引用;间接满足上述初始化过程的情况叫做被动引用。
那么,只有当程序在运行过程中满足主动引用的时候才会初始化一个类,若满足被动引用就不会初始化一个类。
接口的初始化
接口和类都需要初始化,接口和类的初始化过程基本一样,不同点在于:类初始化时,如果发现父类尚未被初始化,则先要初始化父类,然后再初始化自己;但接口初始化时,并不要求父接口已经全部初始化,只有程序在运行过程中用到当父接口中的东西时才初始化父接口(没用到父接口的变量或者方法时不需要初始化父接口)。
例子
被动引用的场景示例
public class Fu{
public static String name = "test";
static{
System.out.println("父类被初始化!");
}
}
public class Zi{
static{
System.out.println("子类被初始化!");
}
}
public static void main(String[] args){
System.out.println(Zi.name);
}
输出结果:
父类被初始化!
test
原因分析:
本示例看似满足初始化时机的第一条:当要获取某一个类的静态成员变量的时候如果该类尚未初始化,则对该类进行初始化。
但由于这个静态成员变量属于Fu类,Zi类只是间接调用Fu类中的静态成员变量,因此Zi类调用name属性属于间接引用,
而Fu类调用name属性属于直接引用,由于JVM只初始化直接引用的类,因此只有Fu类被初始化。
public class A{
public static void main(String[] args){
Fu[] arr = new Fu[10];
}
}
输出结果:
并没有输出“父类被初始化!”
原因分析:
这个过程看似满足初始化时机的第一条:遇到new创建对象时若类没被初始化,则初始化该类。
但现在通过new要创建的是一个数组对象,而非Fu类对象,因此也属于间接引用,不会初始化Fu类。
public class Fu{
public static final String name = "test";
static{
System.out.println("父类被初始化!");
}
}
public class A{
public static void main(String[] args){
System.out.println(Fu.name);
}
}
输出结果:
test
原因分析:
本示例看似满足类初始化时机的第一个条件:获取一个类静态成员变量的时候若类尚未初始化则初始化类。
但是,Fu类的静态成员变量被final修饰,它已经是一个常量。
被final修饰的常量在Java代码编译的过程中就会被放入它被引用的class文件的常量池中(这里是A的常量池)。
所以程序在运行期间如果需要调用这个常量,直接去当前类的常量池中取,而不需要初始化这个类。
JVM的类加载时机的更多相关文章
- 【JVM】类加载时机与过程
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制.下面来总结梳理类加载的五个阶段. 类加载发生在 ...
- 从一道面试题来认识java类加载时机与过程
说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要的内容. 1 开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可 ...
- java类加载时机与过程
转自:http://www.tuicool.com/articles/QZnENv 说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要 ...
- 深入理解JVM(3)——类加载机制
1.类加载时机 类的整个生命周期包括了:加载( Loading ).验证( Verification ).准备( Preparation ).解析( Resolution ).初始化( Initial ...
- 从一道面试题来认识java类加载时机与过程【转】
说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要的内容. 1 开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可 ...
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- 漫谈JVM之类加载机制(篇一)
前言 最近在看一本书,发现代码里用到了Thread.currentThread().getContextClassLoader(),为什么类加载器还与线程有关系呢,为什么不直接使用ClassLoade ...
- 深入理解JVM之类加载
---title: [学习]深入理解JVM之类加载.mddate: 2019-10-20 22:20:06tags: JVM 类加载--- Java类的加载,连接,初始化都是在程序运行期间执行的 ## ...
- JVM:类加载与字节码技术-2
JVM:类加载与字节码技术-2 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 这部分内容在上一篇笔记中: 类文件结构 字节码指令 编译期处理 类加载阶段 ...
随机推荐
- Java反射API研究(2)——java.lang.reflect详细内容与关系
对于最新的java1.8而言,reflect中接口的结构是这样的: java.lang.reflect.AnnotatedElement java.lang.reflect.AnnotatedType ...
- php数组转成php编程代码
将php数组转成可以在php上面运行的编程代码,支持一维及多维数组 <?php //一维数组 $test1 = array(1,2,3); //二维数组 $test2[0] = array( ' ...
- Python2 to python3
概述 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个 ...
- C# winform无边框窗体移动
public partial class MessageHints : Form { //窗体移动API [DllImport("user32.dll")] public stat ...
- Selenium下拉菜单(Select)的操作-----Selenium快速入门(五)
对于一般元素的操作,我们只要掌握本系列的第二,三章即可大致足够.对于下拉菜单(Select)的操作,Selenium有专门的类Select进行处理.文档地址为:http://seleniumhq.gi ...
- Katalon Studio简单使用(二)
距离上一篇更新katalon学习部分已有两个月的时间 ,我的博文的访问量为400多,(*^__^*) 嘻嘻…… 说明还是很多同学在学习这个小tools的.所以再记录下 近两个月来对katalon的体验 ...
- 【转】如何成为一名优秀的web前端工程师(前端攻城师)?
[转自]http://julying.com/blog/how-to-become-a-good-web-front-end-engineer/ 程序设计之道无远弗届,御晨风而返.———— 杰佛瑞 · ...
- python网络编程--socketserver 和 ftp功能简单说明
1. socketserver 我们之前写的tcp协议的socket是不是一次只能和一个客户端通信,如果用socketserver可以实现和多个客户端通信.它是在socket的基础上进行了一层封装,也 ...
- python单引号和双引号的区别
今天在网上爬虫的时候,很奇怪的发现python的字符串既可以用双引号又可以用单引号,于是就上网百度了一下原因. 原来由于字符串中有可能既有双引号又有单引号,例如: 字符串:demo'1'. 这时候就可 ...
- django入门-静态文件-part6
尊重作者的劳动,转载请注明作者及原文地址 http://www.cnblogs.com/txwsqk/p/6517553.html 完全翻译自官方文档 https://docs.djangoproje ...