但是对于初始化阶段,虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):
1)遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
2)使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
5)当使用JDK 1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

这5种场景中的行为称为对一个类进行主动引用。除此之外,所有引用类的方式都不会触发初始化,称为被动引用。
下面举3个例子来说明何为被动引用

public class SuperClass {
public static final String HELLOWORLD = "hello world";
public static int value = 123; static {
System.out.println("SuperClass init!");
}
} public class SubClass extends javaT.SuperClass {
static {
System.out.println("SubClass init!");
}
} public class maintest { public static void main(String[] args) {
//1.
// 上述代码运行之后,只会输出“SuperClass init!”,而不会输出“SubClass init!”。
// 对于静态字段,只有直接定义这个字段的类才会被初始化,
// 因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始
System.out.println(javaT.SubClass.value); //2
// 运行之后发现没有输出“SuperClass init!”,创建动作由字节码指令newarray触发。
javaT.SuperClass[] sca = new javaT.SuperClass[10]; //3
// 没有输出“SuperClass init!”,常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
// 实际上maintest的Class文件之中并没有SuperClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。
System.out.println(javaT.SuperClass.HELLOWORLD);
}
}

运行结果

SuperClass init!
123
hello world

反编译源码:

  public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field javaT/SubClass.value:I
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: bipush 10
11: anewarray #5 // class javaT/SuperClass
14: astore_1
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #6 // String hello world
20: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: return
LineNumberTable:
line 10: 0
line 14: 9
line 19: 15
line 20: 23
LocalVariableTable:
Start Length Slot Name Signature
0 24 0 args [Ljava/lang/String;
15 9 1 sca [LjavaT/SuperClass;

Java类的加载时机的更多相关文章

  1. JVM中java类的加载时机(转载:http://blog.csdn.net/chenleixing/article/details/47099725)

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

  2. jvm系列(一):java类的加载机制

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

  3. Java类的加载

    1.类的加载步骤 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载.连接.初始化三步来实现对这个类的初始化 加载:将class文件读入内存,并为之创建一个Class对象,任何类被使用 ...

  4. Java类的加载、链接和初始化

    一.Java的类加载机制回顾与总结: 我们知道一个Java类要想运行,必须由jvm将其装载到内存中才能运行,装载的目的就是把Java字节代码转换成JVM中的java.lang.Class类的对象.这样 ...

  5. java 类的加载,链接,初始化

    本篇的话题,讨论Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码 ...

  6. Java类的加载与生命周期

    一.概要: 类的生命周期从类的 加载.连接.初始化 开始,到类的 卸载结束: 二.几个阶段: 加载:查找并加载类的二进制数据.(把类的.class文件的二进制数据读入内存,存放在运行时数据区的方法区: ...

  7. Java类的加载 链接 初始化

    原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...

  8. 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...

  9. JVM(1):Java 类的加载机制

    原文出处: 纯洁的微笑 java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang. ...

随机推荐

  1. asp.net session锁导致ajax请求阻塞

    问:为了可以顺序访问Session的状态值,Session是否提供了锁定机制?答:Session实现了Reader/Writer的锁机制:当页面对Session具有可写功能(即页面有<%@Pag ...

  2. 如果报错,使用 journalctl -f -t etcd 和 journalctl -u etcd 来定位问题。

    如果报错,使用 journalctl -f -t etcd 和 journalctl -u etcd 来定位问题.

  3. 在IOS应用中打开另外一个应用的解决方案

    最近要在IOS中实现一个应用启动另外一个应用的功能,搜了一些资料,使用UIApplication的openURL:的方法就能实现,现在整理和大家分享一下! 注册自定义URL协议 首先被启动的应用需要向 ...

  4. Docker命令详解(run篇)

    命令格式:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Usage: Run a command in a new container 中文意思为:通过r ...

  5. JavaScript面向对象之get和set设置读写属性

    之前我们通过this和prototype申明的属性都是可读写的属性,如果想实现单独控制,就必须使用get和set存取期. 基本方法的 步骤一般包含两个步骤,1,使用var关键字定义一个私有属性作为中间 ...

  6. Linux下/usr/bin与/usr/local/bin/区别总结

    Linux下/usr/bin与/usr/local/bin/区别总结 2017年10月13日 12:30:17 2puT 阅读数:15930    版权声明:本文为博主原创文章! github地址:h ...

  7. jQuery相关用法

    #jquery中extend的用法 [1] [2] jQuery.extend( target [, object1 ] [, objectN ] ) Description: Merge the c ...

  8. GIS常用知识列举

    GIS知识分类 我认为GIS知识,大体可分为以下三类. G——测量学.地图学.误差理论等基础——测绘方面 I——数据库.开发——IS方面 S——GIS原理——结合前面两种知识的理念 第一类,是基础,有 ...

  9. Windows10 家庭版 关闭Windows defender

    管理员权限打开cmd,输入下面命令: reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender&quo ...

  10. 阿里云api调用做简单的cmdb

    阿里云api调用做简单的cmdb 1 步骤 事实上就是调用阿里api.获取可用区,比方cn-hangzhou啊等等.然后在每一个区调用api 取ecs的状态信息,最好写到一个excel里面去.方便排序 ...