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 ...
随机推荐
- bzoj 4815: [Cqoi2017]小Q的表格【欧拉函数+分块】
参考:http://blog.csdn.net/qq_33229466/article/details/70174227 看这个等式的形式就像高精gcd嘛-所以随便算一下就发现每次修改(a,b)影响到 ...
- 洛谷 P1251 餐巾计划问题【最小费用最大流】
建图细节比较多,对于每个点i,拆成i和i',i表示用的餐巾,i'表示脏餐巾,连接: (s,i,r[i],p)表示在这一天买新餐巾 (i,t,r[i],0)表示这一天用了r[i]的餐巾 (s,i+n,r ...
- 【转】Postman 使用方法详解
1.Postman背景介绍 用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具.今天给大家介 ...
- 如何快捷安装并配置MySQL 下载破解Navicat for mysql
首先,要先下载MySQL,进官网下载相应的mysql版本,这个不收费,实在不知道的可以参考一下这篇:https://blog.csdn.net/qq_37172528/article/details/ ...
- Unix\Linux | 总结笔记 | 查看文件的方式
0 目录 vi cat head tail more less 1.vi vi编辑器的内置命令 有些内置命令使用键盘组合键即可完成,有些内置命令则需要以冒号“:”开头输入.常用内置命令如下: Ctrl ...
- AngularJs 的ng-include指令的使用
AngularJs通过指令ng-include来将页面中共用的模块分离出来,这个功能和mvc里面的分部页的作用一样的. 先看文件的结构: 父页面: <!DOCTYPE html> < ...
- Android 线程池系列教程(4) 启动线程池中的线程和中止池中线程
Running Code on a Thread Pool Thread 上一课 下一课 1.This lesson teaches you to Run a Runnable on a Thre ...
- sed练习第一节
ed语法和基本命令 employee.txt文件内容如下: 101,John Doe,CEO 102,Jason Smith,IT Manager 103,Raj Reddy,Sysadmin 104 ...
- Java 线程 —— Wait (等待)和 Notify(唤醒)
Wait (等待)和 Notify(唤醒) 这里讲了一个Wait (等待)和 Notfity(唤醒),下面这个实例(工厂,商店,消费者) 额,然后,你就知道了,需要写三个类:工厂类,Shop类,消费者 ...
- AJPFX总结Socket的低层次Java网络编程
Socket的低层次Java网络编程 1 Socket通讯 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接. ...