Java虚拟机规范中并没有进行强制玉树什么情况下需要开始类加载过程。但是对于初始化阶段,虚拟机规范则是严格规定了有且仅有5种情况必须立即对类进行“初始化”(而加载,验证,准备自然需要在此之前开始):

1.遇到new,getstatic,putstatic,或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这四条指令单最常见的Java代码场景是:使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰,已在变异期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

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

3.当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先出法其父类的初始化。

4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

5.当使用JDK1.7的动态语言支持时,如果一个Java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic,REF_outStatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

对于这五种会触发类进行初始化的场景,虚拟机规范中是用来一个很强烈的现定于:“有且仅有”,这5种场景中的行为称为一个类进行主动引用。

看下面的例子:

  1. package logan.classload.study;
  2.  
  3. public class SuperClass {
  4. static{
  5. System.out.println("SuperClass init!");
  6. }
  7. public static int value=123;
  8.  
  9. }
  1. package logan.classload.study;
  2.  
  3. public class SubClass extends SuperClass {
  4. static{
  5. System.out.println("SubClass init!");
  6. }
  7.  
  8. }
  1. package logan.classload.study;
  2.  
  3. public class NotInitialization {
  4.  
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. System.out.println(SubClass.value);
  8.  
  9. }
  10.  
  11. }
  1. SuperClass init!
  2. 123

思考一下输出结果

对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。至于是否要触发子类的加载和验证,在虚拟机规范中并未明确规定。这点取决于虚拟机的具体实现。对于Sun HotSpot来说,可通过-XX:+TraceClassLoading参数观察到此操作会导致子类的加载。

看下面一个例子:

  1. package logan.classload.study;
  2.  
  3. public class NotInitialization {
  4.  
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. SuperClass[]sca = new SuperClass[10];
  8.  
  9. }
  10.  
  11. }
  1. 没有输出

想想输出结果

运行之后发现没有输出,“SuperClass init!”说明没有处罚类SuperClass的初始化。但是这段代码里面出发了另外一个名为“[Llogan.classload.study.SuperClass”的类的初始化阶段,对于用户代码来说这并不是一个合法的类名称,他是一个由虚拟机自动生成的,直接继承与java.lang.Object的子类,创建动作由字节码指令newarray触发。

这个类代表了一个元素类型为logan.classload.SuperClass的一位数组,数组中应有的属性和方法(用户可以直接使用的只有被修饰为public的length属性和clone()方法)都是现在这个类里。

看下面一个例子

  1. package logan.classload.study;
  2.  
  3. public class ConstClass {
  4. static{
  5. System.out.println("ConstClass init!");
  6. }
  7. public static final String HelloWorld = "hello world";
  8.  
  9. }
  1. package logan.classload.study;
  2.  
  3. public class NotInitialization {
  4.  
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. System.out.println(ConstClass.HelloWorld);
  8.  
  9. }
  10.  
  11. }
  1. hello world

猜一下输出结果

输出里面没有输出“ConstClass init!”,这是因为虽然在Java源码中引用了ConstClass类中放常量HelloWorld,但是其实在变异阶段通过常量传播优化,已经将此常量的值“hello world”存储到NotInitialization类的常量池中,以后NotInitialization对常量ConstClass.HelloWorld的引用实际都被转化为NotInitialization类对自身常量池的引用了。

也就是说,实际上NotInitialization的Class文件之中并没有ConstClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。

接口的加载过程与类加载过程稍微有一些不同,针对接口需要做一下特殊说明:接口也有初始化过程,这点与类类是一致的。上面的代码都是用静态语句块“static{}”来输出初始化信息的,而接口中不能使用“static{}”语句块,但是编译器仍然会为接口生成“<client>()”类构造器,用于初始化接口中多定义的成员变量。接口与类真正有所区别的是前面讲述的5种“有且仅有”需要开始初始化场景中的第三种:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父类接口全部完成初始化,只有在真正使用到父类接口的时候(如引用接口中定义的常量)才会初始化。

java类什么时候初始化?的更多相关文章

  1. Java 类成员的初始化顺序

    Java 类成员的初始化顺序 前言:开发中碰到一个Java文件中有很多的成员变量,包括静态和非静态的,还有很多的初始化方法,很好奇这些成员的初始化顺序,在这里作个研究.   1  无继承情况下的Jav ...

  2. Java类的成员初始化顺序

    Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...

  3. java类的成员初始化顺序和初始化块知识

    java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...

  4. Java类和对象初始化

    类的生命周期: Java类的初始化: 本阶段负责为类变量赋正确的初始值.(类变量即静态变量) Java编译器把所有的类变量初始化语句和静态初始化器通通收集到<clinit>方法中,该方法只 ...

  5. Java类、实例初始化的顺序

    求如下 java 代码的输出?? class T implements Cloneable{ public static int k = 0; public static T t1 = new T(& ...

  6. java类中元素初始化顺序

    结论:对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器. public class Test4 { @Tes ...

  7. Java类与对象初始化的过程(一道经典的面试题)

    本文不再以ClassLoader的视角解释这些问题. 首先,Java代码有个特点,就是成员变量可以在前面的方法中使用,在后面定义.这一特性,很多人说Java了不起,可是为什么呢?Java为何能够这样呢 ...

  8. Java类的变量初始化顺序

    大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台 ...

  9. Java 类的成员初始化顺序

    做个简单笔录,就当是重温下基础知识. 1.先看代码: package com.test; public class Test { public static void main(String[] ar ...

随机推荐

  1. OSI模型网络分层

    OSI TCP/IP --- ------- 应用层 表示层 应用层 会话层 ----- ------- 传输层 TCP UDP ----- ------- 网络层 IPv4/IPv6 ----- - ...

  2. js 数组的所有操作

    js的数组操作有很多,这里记录了常用的和不常用的数组操作方法. 一.数组的创建 数组的创建有两种方法,一种是通过字面量,另一种是通过Array构造函数. 1.字面量 var num1 = [1,2,3 ...

  3. 添加linux开机启动任务

    对于系统里面设置的开机启动程序 先来看一个例子nginx启动脚本 #!/bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $ ...

  4. Qt之界面实现技巧-- 窗体显示,绘制背景,圆角,QSS样式

    转自 --> http://blog.sina.com.cn/s/blog_a6fb6cc90101dech.html 总结一下,在开发Qt的过程中的一些技巧!可遇而不可求... 一.主界面 1 ...

  5. [原创]Java开发在线编辑Word同时实现全文检索

    一.背景介绍 Word文档与日常办公密不可分,在实际应用中,当某一文档服务器中有很多Word文档,假如有成千上万个文档时,用户查找打开包含某些指定关键字的文档就变得很困难,一般情况下能想到的解决方案是 ...

  6. Vue从接口请求数据

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. django学习笔记(一)视图和url配置

    1.开始一个项目: 进入创建的目录,然后: django-admin startproject myblog 2.启动开发服务器: python manage.py runserver 注:默认是80 ...

  8. C++中函数重载

    C++中函数重载使用顶层const修饰参数和不使用const修饰参数效果是一样的,如果定义了这样的重载函数会报函数重定义的错误. 追其原因,C++中的函数传递方式有三种,一种是值传递,就是拷贝,一种是 ...

  9. H264 NALU 使用PS封装 RTP发送

    最近由于项目平台需求,要将H264 NALU封装为PS再用RTP发送,PS封装按照ISO DEC-13818-1标准.一个PS包包含PS Header, PES Header, PS system h ...

  10. 【转】Lucas定理 & 逆元学习小结

    (From:离殇灬孤狼) 这个Lucas定理是解决组合数的时候用的,当然是比较大的组合数了.比如C(1000000,50000)% mod,这个mod肯定是要取的,要不算出来真的是天文数字了. 对于一 ...