JVM类加载过程

JVM类加载过程分为几个阶段,分别是加载验证准备解析初始化加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初始值,解析是把常量池内的符号引用替换为直接引用,初始化是执行所有静态变量的赋值动作和静态语句块中的语句。更多详尽分析请阅读之前的文章《JVM的类加载机制全面解析》,这里不再赘述了。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

类初始化的时机

对于我们开发人员,我认为应该具体了解一下初始化阶段什么时候在开始。JVM规范对此做了严格规范,有且只有以下5种情况必须对类进行初始化:

  1. 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类没有被初始化过,就需要先进行初始化。对于字节码指令不了解的同学,可能就是一脸蒙圈了。我们来说人话,就是:使用new关键字实例化对象的时候、读取和设置一个类的静态字段(不被final修饰的)和调用一个类的静态方法的时候。这样说更容易被理解一些。

  2. 使用java.lang.reflect包中的方法对类进行反射调用的时候,如果类没有被初始化过,就需要先进行初始化。

  3. 当初始化一个类的时候,如果发现它的父类还没有被初始化过,就需要先初始化它的父类。

  4. JVM会先初始化要执行的主类,也是包含main()方法的那个类。

  5. 当使用JDK 1.7的动态语言支持时,如果java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic(使用MethodHandle读取类的静态字段)、REF_putStatic(使用MethodHandle设置类的静态字段)、REF_invokeStatic(使用MethodHandle调用类的静态方法)的方法句柄时,如果这个方法句柄没有被初始化过,就需要先进行初始化。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

被动引用

刚刚提到的5种情况,都会触发初始化,这些行为为称为对一个类的主动引用。除了这些以外,所有引用类的方式都不会触发初始化,被为被动引用。为了更好的理解,下面举几个被动引用的例子。

通过子类引用父类的静态变量

public class SuperClass {
static {
System.out.println("父类正在初始化");
} public static String name = "万猫学社";
}
public class SubClass extends SuperClass {
static {
System.out.println("子类正在初始化");
}
}
public class OneMoreStudy {
public static void main(String[] args) {
System.out.println(SubClass.name);
}
}

对于静态变量,只有直接定义这个变量的类才会被初始化,通过子类引用父类中定义的静态变量,只会触发父类的初始化而不会触发子类的初始化,运行的结果是:

父类正在初始化
万猫学社

结果中并没有“子类正在初始化”。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

通过数组定义来引用类

public class OneMoreStudy {
public static void main(String[] args) {
SuperClass[] arrays = new SuperClass[10];
System.out.println("数组元素个数:" + arrays.length);
}
}

这段代码中使用之前的SuperClass类,定义了一个SuperClass类的一维数组,运行后的结果是:

数组元素个数:10

结果中并没有“父类正在初始化”,说明并没有触发SuperClass类的初始化。实际上,有一个名为“[LSuperClass”的类被初始化了,它是由JVM自动生成的、直接继承于java.lang.Object,创建动作由字节码指令newarray触发。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

常量

public class ConstClass {
static {
System.out.println("有常量的类正在初始化");
} public static final String NAME = "万猫学社";
}
public class OneMoreStudy {
public static void main(String[] args) {
System.out.println(ConstClass.NAME);
}
}

常量在编译阶段会存入调用类的常量池中,本质没有直接引用到定义的常量的类,不会触发定义常量的类的初始化,所以运行的结果是:

万猫学社

结果中并没有“有常量的类正在初始化”。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

接口初始化的时机

接口也有初始化过程,和类是一致的。不过接口中不能使用“static{}”语句块,但编译器仍然会为接口生成“clinit()”类构造器,用于初始化接口中所定义的成员变量。

接口初始化的时机,基本和之前提到的类的5种情况基本一致,唯一不一样的是第3种情况:在一个类被初始化时,它的父类也必须被初始化,但是一个接口被初始化时,它的父接口并不要求被初始化。只有在真正使用到父接口时才会被初始化,比如:引用父接口中定义的常量。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

结语

这次主要分享了类在什么时候被初始化,共有5种情况。除了这种5种情况的引用叫做被动引用,同时举了3个被动引用的例子。同时,也提到初始化接口和类有什么不同。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

全面解析JVM加载中初始化的时机的更多相关文章

  1. JVM加载的初始化类

    首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

  2. JVM加载类的过程,双亲委派机制中的方法

    JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载  1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...

  3. 关于JVM加载class文件和类的初始化

    关于JVM加载class文件和类的初始化 1.JVM加载Class文件的原理机制 1.1.装载 查找并加载类的二进制数据 1.2.链接 验证:确保被加载类的正确性.(安全性考虑) 准备:为类的静态变量 ...

  4. jvm加载类(更新中)

    作为jvm的用户,从使用者角度来看,我们给jvm输入一个class文件,得到了一个Class对象.我们可以猜想下jvm加载类的过程:class文件有规定的格式,jvm去解析class文件流,读magi ...

  5. Java提高篇——JVM加载class文件的原理机制

    在面试java工程师的时候,这道题经常被问到,故需特别注意. 1.JVM 简介 JVM 是我们Javaer 的最基本功底了,刚开始学Java 的时候,一般都是从“Hello World ”开始的,然后 ...

  6. JVM学习(二)JVM加载类

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

  7. Java 类的加载与初始化

    本文结构: 1.先看几道题 2.类的加载于初始化 (1)类的加载 (2)类的初始化 (a)会发生类的初始化的情况 (b)不会发生类的初始化的情况 首先看几道题. 解析可在看完讲解后再看 Demo1 p ...

  8. JVM加载class文件的原理

    当Java编译器编译好.class文件之后,我们需要使用JVM来运行这个class文件.那么最开始的工作就是要把字节码从磁盘输入到内存中,这个过程我们叫做[加载 ].加载完成之后,我们就可以进行一系列 ...

  9. 【JVM】查看JVM加载的类及类加载器的方法

    查看JVM加载了哪些类 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息. java -verbose:class 在程序运行的时候有多少类被加载!你可以用ve ...

随机推荐

  1. 测试工程师,选择python还是java?

    问:“你平时工作中,用java多还是用python多”? 答:“都还可以,根据具体的场景选择不同的语言”. 问:“比如说呢”? 答:“开发自己的测试平台,肯定会选择java:在centos服务器跑一些 ...

  2. 使用Typescript重构axios(七)——实现基础功能:处理响应header

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  3. UiPath之数据透视表

    今天给各位小伙伴们讲讲如何使用UiPath来创建数据透视表,相信大家在Execl中经常会使用. ---小U的QQ群(714733686):小U的订阅号[UiPath8888]--- 在UiPath里面 ...

  4. 1000m交叉网线最简单做法

    1-3,2-6,3-1,4-7,5-8,6-2,7-4,8-5 1,2,3,4,5,6,7,8即为网线内部8跟线编号,两头颜色和数字要对应.

  5. PHP代码安全有必要了解下

    攻击者通过构造恶意SQL命令发送到数据库,如果程序未对用户输入的 SQL命令执行判断过滤,那么生成的SQL语句可能会绕过安全性检查,插入其他用于修改后端数据库的语句,并可能执行系统命令,从而对系统造成 ...

  6. mysql提示Packet for query is too large (1142 > 1024)解决方案

    注:最近mysql一直提示如下错误 Packet for query is too large (1185 > 1024). You can change this value on the s ...

  7. mysql 创建用户及授权(1)

    一. 创建用户 命令: CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明: username:你将创建的用户名 host:指定该用户 ...

  8. 【前端知识体系-CSS相关】CSS工程化方案

    1.如何解决CSS的模块化问题? 使用Less,Sass等CSS预处理器 使用PostCSS插件(postcss-import/precss) 使用webpack处理CSS(css-loader + ...

  9. php使用cUrl方法 get、post请求

    php使用curl方法,请确保已经开启curl扩展.传送门:http://www.cnblogs.com/wgq123/p/7450667.html /**Curl请求get方法 *@$url Str ...

  10. 分析facebook的AsyncDisplayKit框架,async-display使用async-transaction

    上一篇<分析facebook的AsyncDisplayKit框架中的Transaction的工作原理>介绍了fb的asdk的异步事务ASAsyncTransaction,本篇介绍其在asd ...