原文: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加载顺序的更多相关文章

  1. web.xml加载顺序

    一 1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Ser ...

  2. web.xml文件加载顺序

    1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Servl ...

  3. web.xml 中的listener、 filter、servlet 加载顺序及其详解

    在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰. 首先可以肯定的是 ...

  4. css样式加载顺序及覆盖顺序深入理解

    注:内容转载 很多的新手朋友们对css样式加载顺序和覆盖顺序的理解有所偏差,下面用示例为大家详细的介绍下,感兴趣的朋友不要错过 { height: 100%; width: 200; position ...

  5. Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序

    直接上代码: 代码1: public class ConstroctTest { private static ConstroctTest test = new ConstroctTest(); // ...

  6. DOM加载顺序

    最近一直在困扰dom的加载顺序问题,经常会遇到以为绑定好的事件不响应等情况,一头雾水,直到请教了周围的同事,才发现了解dom的加载顺序是多么的重要. 关于这个问题,其实网上已经有一些介绍,但是我觉得并 ...

  7. PHP 依赖注入,从此不再考虑加载顺序

    说这个话题之前先讲一个比较高端的思想--'依赖倒置原则' "依赖倒置是一种软件设计思想,在传统软件中,上层代码依赖于下层代码,当下层代码有所改动时,上层代码也要相应进行改动,因此维护成本较高 ...

  8. MVC中 _ViewStart _Layout Index三个页面中的加载顺序

    MVC学习中忽然想到一个问题.. 在访问一个Index.cshtml页面时, MVC的加载顺序是怎么样的呢? 首先说下我的结论 . _ViewStart.cshtml . Index.cshtml . ...

  9. WebForm中搭配母版页和用户控件页时候的事件加载顺序

    在生产环境中,一个内容页(aspx)可能会包含数个用户控件(ascx),而每个控件可能都会涉及到数据库访问. 如果在内容页.母版页.控件页中各自使用自己的数据库访问方法,会造成很大的运行成本. 这样的 ...

  10. 详解web.xml中元素的加载顺序

    一.背景 最近在项目中遇到了启动时出现加载service注解注入失败的问题,后来经过不懈努力发现了是因为web.xml配置文件中的元素加载顺序导致的,那么就抽空研究了以下tomcat在启动时web.x ...

随机推荐

  1. bzoj 2815

    http://www.cnblogs.com/JS-Shining/archive/2013/01/12/2857429.html 题面 题解上写了用什么dominator tree,吓晕了,看了看, ...

  2. 2-11 tensorflow常量变量定义

    D:\Users\ZHONGZHENHUA\Anaconda3\envs\tensorflow\Lib\site-packages\tensorflow https://developer.nvidi ...

  3. 13_传智播客iOS视频教程_OC程序的编译链接

    C程序的编译.链接.执行怎么来的?在.C文件里面写上符合C语言部分的源代码.OC也是一样的.记住:OC程序的后缀名是.m. 为什么要链接?第一个.o的目标文件里面它启动不了.因为它没有启动代码我们要加 ...

  4. 51nod 1122 机器人走方格 V4 【矩阵快速幂】

    首先建立矩阵,给每个格子编号,然后在4*4的格子中把能一步走到的格子置为1,然后乘n次即可,这里要用到矩阵快速幂 #include<iostream> #include<cstdio ...

  5. 多选下拉框(select 下拉多选)

    方法一:使用multiple-select.js和multiple-select .css实现 HTML代码: <select id='checkedLevel' style="wid ...

  6. 利用OneDNS同步chrome数据

    将DNS服务器改成OneDNS的 117.50.11.11 备用改为 117.50.22.22 然后刷新自己的DNS缓存,接着测试一下https://test.onedns.net即可 这样既可以正常 ...

  7. [CF1109F]Sasha and Algorithm of Silence's Sounds

    题意 有一个\(n*m\)的网格,每个格子有一个数,为\(1\)~\(n * m\)的排列 一个区间\((1<=l<=r<=n*m)\)是好的,当且仅当:数值在该区间内的格子,构成一 ...

  8. [Usaco2005 Nov]Asteroids

    Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape o ...

  9. Activity状态图、生命周期图(超详细),onSaveInstanceState只保存、恢复基本ui数据,持久数据不在这里保存。

    1.Activity状态图 2.Activity生命周期简图 启动Activity: onCreate()—>onStart()—>onResume(),Activity进入running ...

  10. html 测试

    斯蒂芬斯蒂芬 20:23你过来吧,我们好好谈一谈 好好学习 21:22这是一个无法避免的错误 作为一个新手,我在学习HTML文件的格式,我觉得博客园的编辑器很棒, 查看这些源代码让我学习到了许多知识. ...