java类什么时候初始化?
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种场景中的行为称为一个类进行主动引用。
看下面的例子:
package logan.classload.study; public class SuperClass {
static{
System.out.println("SuperClass init!");
}
public static int value=123; }
package logan.classload.study; public class SubClass extends SuperClass {
static{
System.out.println("SubClass init!");
} }
package logan.classload.study; public class NotInitialization { public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(SubClass.value); } }
SuperClass init!
123
思考一下输出结果
对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。至于是否要触发子类的加载和验证,在虚拟机规范中并未明确规定。这点取决于虚拟机的具体实现。对于Sun HotSpot来说,可通过-XX:+TraceClassLoading参数观察到此操作会导致子类的加载。
看下面一个例子:
package logan.classload.study; public class NotInitialization { public static void main(String[] args) {
// TODO Auto-generated method stub
SuperClass[]sca = new SuperClass[10]; } }
没有输出
想想输出结果
运行之后发现没有输出,“SuperClass init!”说明没有处罚类SuperClass的初始化。但是这段代码里面出发了另外一个名为“[Llogan.classload.study.SuperClass”的类的初始化阶段,对于用户代码来说这并不是一个合法的类名称,他是一个由虚拟机自动生成的,直接继承与java.lang.Object的子类,创建动作由字节码指令newarray触发。
这个类代表了一个元素类型为logan.classload.SuperClass的一位数组,数组中应有的属性和方法(用户可以直接使用的只有被修饰为public的length属性和clone()方法)都是现在这个类里。
看下面一个例子
package logan.classload.study; public class ConstClass {
static{
System.out.println("ConstClass init!");
}
public static final String HelloWorld = "hello world"; }
package logan.classload.study; public class NotInitialization { public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(ConstClass.HelloWorld); } }
hello world
猜一下输出结果
输出里面没有输出“ConstClass init!”,这是因为虽然在Java源码中引用了ConstClass类中放常量HelloWorld,但是其实在变异阶段通过常量传播优化,已经将此常量的值“hello world”存储到NotInitialization类的常量池中,以后NotInitialization对常量ConstClass.HelloWorld的引用实际都被转化为NotInitialization类对自身常量池的引用了。
也就是说,实际上NotInitialization的Class文件之中并没有ConstClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。
接口的加载过程与类加载过程稍微有一些不同,针对接口需要做一下特殊说明:接口也有初始化过程,这点与类类是一致的。上面的代码都是用静态语句块“static{}”来输出初始化信息的,而接口中不能使用“static{}”语句块,但是编译器仍然会为接口生成“<client>()”类构造器,用于初始化接口中多定义的成员变量。接口与类真正有所区别的是前面讲述的5种“有且仅有”需要开始初始化场景中的第三种:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父类接口全部完成初始化,只有在真正使用到父类接口的时候(如引用接口中定义的常量)才会初始化。
java类什么时候初始化?的更多相关文章
- Java 类成员的初始化顺序
Java 类成员的初始化顺序 前言:开发中碰到一个Java文件中有很多的成员变量,包括静态和非静态的,还有很多的初始化方法,很好奇这些成员的初始化顺序,在这里作个研究. 1 无继承情况下的Jav ...
- Java类的成员初始化顺序
Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...
- java类的成员初始化顺序和初始化块知识
java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...
- Java类和对象初始化
类的生命周期: Java类的初始化: 本阶段负责为类变量赋正确的初始值.(类变量即静态变量) Java编译器把所有的类变量初始化语句和静态初始化器通通收集到<clinit>方法中,该方法只 ...
- Java类、实例初始化的顺序
求如下 java 代码的输出?? class T implements Cloneable{ public static int k = 0; public static T t1 = new T(& ...
- java类中元素初始化顺序
结论:对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器. public class Test4 { @Tes ...
- Java类与对象初始化的过程(一道经典的面试题)
本文不再以ClassLoader的视角解释这些问题. 首先,Java代码有个特点,就是成员变量可以在前面的方法中使用,在后面定义.这一特性,很多人说Java了不起,可是为什么呢?Java为何能够这样呢 ...
- Java类的变量初始化顺序
大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台 ...
- Java 类的成员初始化顺序
做个简单笔录,就当是重温下基础知识. 1.先看代码: package com.test; public class Test { public static void main(String[] ar ...
随机推荐
- parseInt、parseFloat、Number、Boolean、valueOf总结
parseInt(string, radix) 功能: 将字符串转换为十进制的数字 radix: string的进制,没有时根据string进行判断: 1~9开头 十进制 0x开头 16进制 0开头 ...
- centos 中 增强web服务器安全
一.修改ssh连接的默认端口: 1.1 用root 连接进入系统: 1.2 修改ssh的配置文件 #vi /etc/ssh/sshd_config 在13行找到#Port 22 (默认端口22) 1. ...
- html5新特性contenteditable 属性更容易实现动态表单
介绍html5新特性的一个属性:contenteditable 作用域全局.所有的块标签都可以,例如:span.p.div.td等标签.但是,不可以作用域<br/>类型的标签. conte ...
- Kafka- Kafka架构功能
Kafka是一个高吞吐量的分布式消息系统,一个分布式的发布-订阅消息系统.Kafka是一种快速,可拓展的,设计内在就是分布式的,分区的可复制的提交日志服务. Apache Kafka与传统消息系统相比 ...
- java:maven中webapp下的jsp不能访问web-inf下面的bean
java:maven中webapp下的jsp不能访问web-inf下面的bean 当然 WEB-INF下面的文件是不能访问的,只能吧jsp文件放入到WEB-INF下面,然后通过配置WEB-INF下we ...
- ListOperations
RedisOperations<K,V> getOperations() V index(K key, long index) V leftPop(K key) V leftPop( ...
- 分享知识-快乐自己:SpringBoot集成热部署配置(一)
摘要: 热部署与热加载: ava热部署与Java热加载的联系和区别: 1):Java热部署与热加载的联系: 1.不重启服务器编译/部署项目 2.基于Java的类加载器实现 2):Java热部署与热加载 ...
- 机器学习(十七)— SVD奇异值分解
奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...
- 用一句SQL取出第 m 条到第 n 条记录的方法
1 --从Table 表中取出第 m 条到第 n 条的记录:(Not In 版本)2 3 SELECT TOP n-m+1 * 4 FROM Table 5 WHERE (id NOT IN (SEL ...
- 解编码框架的比较(protobuf,thrift,Marshalling,xml)
1.ProtoBuf 特点: 1.结构化数据存储格式 2.高效的解编码性能. 3.语言无关,平台无关,扩展性好. 4.官方支持java,c++,python三种语言. 5.性能比较好 (与之对比xml ...