Class加载顺序
原文:https://blog.saymagic.cn/2017/07/01/class-common-question.html
类的初始化顺序是怎样的?
我们尝试从class文件中找到答案。来看这样的一段代码:
public class InitialOrderTest {
public static String staticField = " StaticField";
public String fieldFromMethod = getStrFromMethod();
public String fieldFromInit = " InitField";
static {
System.out.println( "Call Init Static Code" );
System.out.println( staticField );
}
{
System.out.println( "Call Init Block Code" );
System.out.println( fieldFromInit );
System.out.println( fieldFromMethod );
}
public InitialOrderTest()
{
System.out.println( "Call Constructor" );
}
public String getStrFromMethod(){
System.out.println("Call getStrFromMethod Method");
return " MethodField" ;
}
public static void main( String[] args )
{
new InitialOrderTest();
}
}
结果:

我们来一一来看一下它的class文件中的内容,首先是有一个static方法区:
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: ldc #14 // String StaticField
2: putstatic #15 // Field staticField:Ljava/lang/String;
5: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
8: ldc #16 // String Call Init Static Code
10: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
16: getstatic #15 // Field staticField:Ljava/lang/String;
19: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: return
Java编译器在编译阶段会将所有static的代码块收集到一起,形成一个特殊的方法,这个方法的名字叫做clinit, 这个名字容易让我们联想到构造函数的名称叫做init,但与构造函数不同,这个方法在Java层中是调用不到的,并且,这个函数是在这个类被加载时,由虚拟机进行调用。注意的是,是类被加载,而不是类被初始化成实例。所以,静态代码块的加载优先于普通的代码块,也优先于构造函数。这属于虚拟机规定的范畴,我们不做更深入的探讨。
在Class文件中,是没有为普通方法区开辟类似于clinit这种方法的,而是将所有普通方法区的代码都合并到了构造函数中,我们直接来看构造函数:
public InitialOrderTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_0
6: invokevirtual #2 // Method getStr:()Ljava/lang/String;
9: putfield #3 // Field field:Ljava/lang/String;
12: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
15: aload_0
16: getfield #3 // Field field:Ljava/lang/String;
19: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
22: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
25: ldc #6 // String Init Block
27: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
33: ldc #7 // String Constructor
35: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: return
通过分析构造函数,我们就可以对一个实例初始化的顺序一清二楚,首先,0,1在构造函数中调用了父类的构造函数,接着,4、5、6、9为成员变量进行赋值,25、27在执行实例的代码块,最后,33、35才是执行我们Java文件中编写的构造函数的代码。这样,一个普通类的初始化顺序大致如下:
静态代码按照顺序初始化 -> 父类构造函数 -> 变量初始化 -> 实例代码块 -> 自身构造函数
Class加载顺序的更多相关文章
- web.xml加载顺序
一 1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Ser ...
- web.xml文件加载顺序
1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Servl ...
- web.xml 中的listener、 filter、servlet 加载顺序及其详解
在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰. 首先可以肯定的是 ...
- css样式加载顺序及覆盖顺序深入理解
注:内容转载 很多的新手朋友们对css样式加载顺序和覆盖顺序的理解有所偏差,下面用示例为大家详细的介绍下,感兴趣的朋友不要错过 { height: 100%; width: 200; position ...
- Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序
直接上代码: 代码1: public class ConstroctTest { private static ConstroctTest test = new ConstroctTest(); // ...
- DOM加载顺序
最近一直在困扰dom的加载顺序问题,经常会遇到以为绑定好的事件不响应等情况,一头雾水,直到请教了周围的同事,才发现了解dom的加载顺序是多么的重要. 关于这个问题,其实网上已经有一些介绍,但是我觉得并 ...
- PHP 依赖注入,从此不再考虑加载顺序
说这个话题之前先讲一个比较高端的思想--'依赖倒置原则' "依赖倒置是一种软件设计思想,在传统软件中,上层代码依赖于下层代码,当下层代码有所改动时,上层代码也要相应进行改动,因此维护成本较高 ...
- MVC中 _ViewStart _Layout Index三个页面中的加载顺序
MVC学习中忽然想到一个问题.. 在访问一个Index.cshtml页面时, MVC的加载顺序是怎么样的呢? 首先说下我的结论 . _ViewStart.cshtml . Index.cshtml . ...
- WebForm中搭配母版页和用户控件页时候的事件加载顺序
在生产环境中,一个内容页(aspx)可能会包含数个用户控件(ascx),而每个控件可能都会涉及到数据库访问. 如果在内容页.母版页.控件页中各自使用自己的数据库访问方法,会造成很大的运行成本. 这样的 ...
- 详解web.xml中元素的加载顺序
一.背景 最近在项目中遇到了启动时出现加载service注解注入失败的问题,后来经过不懈努力发现了是因为web.xml配置文件中的元素加载顺序导致的,那么就抽空研究了以下tomcat在启动时web.x ...
随机推荐
- Ceph之对象存储网关RADOS Gateway(RGW)
一.Ceph整体架构及RGW在Ceph中的位置 1.Ceph的整体架构 Ceph是一个统一的.分布式的的存储系统,具有优秀的性能.可靠性和可扩展性.Ceph支持对象存储(RADOSGW).块存储(RB ...
- 51nod 1222 最小公倍数计数【莫比乌斯反演】
参考:https://www.cnblogs.com/SilverNebula/p/7045199.html 所是反演其实反演作用不大,又是一道做起来感觉诡异的题 转成前缀和相减的形式 \[ \sum ...
- Android项目通过Android Debug Database实时查看本地Sqlite数据库内容
前几天写Android项目时,想和Sqlyog那样图形化查看数据库中的文件,由于Android自带小型的Sqlite轻量级数据库,在查找方法时发现了一个特别简单适用的方法,纪录一下. 在android ...
- Jmeter常见问题汇总(不断更新ing)
1.测试计划中有多个线程组执行时,为了防止线程组间的相互干扰,需要如下设置一下: 2,接口测试中的上传字段为汉字时需要进行什么形式的转码? 方法一:需要把编码复选框勾选,才能正常通过接口查询数 ...
- 暑期训练狂刷系列——poj 3468 A Simple Problem with Integers (线段树+区间更新)
题目连接: http://poj.org/problem?id=3468 题目大意: 给出n个数,有两种操作: 1:"C a b c",[a,b]中的每一个数都加上c. 2:&qu ...
- POJ 3683 Priest John's Busiest Day
看这个题目之前可以先看POJ2186复习一下强联通分量的分解 题意:给出N个开始时间和结束时间和持续时间三元组,持续时间可以在开始后或者结束前,问如何分配可以没有冲突. -----–我是分割线---- ...
- multiset || 线段树 HDOJ 4302 Holedox Eating
题目传送门 题意:一个长度L的管子,起点在0.n次操作,0 p表示在p的位置放上蛋糕,1表示去吃掉最近的蛋糕(如果左右都有蛋糕且距离相同,那么吃同方向的蛋糕),问最终走了多少路程 分析:用multis ...
- 加密解密(4)SSL协议及HTTPS握手过程
SSL协议 简介 SSL (Secure Sockets Layer 安全套接层)是一个安全协议,它提供使用 TCP/IP 的通信应用程序间的隐私与完整性.因特网的 超文本传输协议 (HTTP)使用 ...
- java中的位预算
public class Demo { public static void main(String[] args) { byte num1 = 3; byte num2 = 5; /*位预算 *nu ...
- Xcode7 使用AFNetWorking 报错 添加Security.framework
Undefined symbols for architecture x86_64: "_SecCertificateCopyData", referenced from: _AF ...