java程序的加载过程
昨天笔试阿里有个求java程序加载过程的题目很是复杂,回来研究了好久才有点明白,整理一下。原题代码如下,判断输出:
public class StaticTest {
public static int k=0;
public static StaticTest s1=new StaticTest("s1");
public static StaticTest s2=new StaticTest("s2");
public static int i=print("i");
public static int n=99;
public int j=print("j");
{
print("构造块");
}
static
{
print("静态块");
}
public static int print(String s)
{
System.out.println(++k+":"+s+"\ti="+i+"\tn="+n);
++n;
return ++i;
}
public StaticTest(String s)
{
System.out.println(++k+":"+s+"\ti="+i+"\tn="+n);
++i;
++n;
}
public static void main(String[] args) {
new StaticTest("init");
}
}
首先给出代码输出:
1:j i=0 n=0
2:构造块 i=1 n=1
3:s1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:s2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
没想到只是创建了一个对象,居然执行了这么多语句!下面我们逐条分析每条输出语句。
首先我们需要对java程序的加载过程有个大概的了解:第一执行类中的静态代码,包括静态成员变量的初始化和静态语句块的执行;第二执行类中的非静态代码,包括非静态成员变量的初始化和非静态语句块的执行,最后执行构造函数。在继承的情况下,会首先执行父类的静态代码,然后执行子类的静态代码;之后执行父类的非静态代码和构造函数;最后执行子类的非静态代码和构造函数。用图表示如下:
第一条语句打印的是j相关的内容,所以执行了第7行代码。很明显该行代码执行的是非静态变量的赋值操作,这似乎不符合上述java程序加载规则。我们按照前述规则执行一下代码,首先会执行静态变量k的赋值,然后创建该类的一个静态实例。这时我们就会发现,第一条打印语句可能和该类的这个静态实例对象有关。我们尝试着创建这个静态实例,这时的程序加载过程又变为上述标准的加载过程:首先执行静态代码,然后非静态,最后构造函数。由于静态代码的执行是按代码的先后顺序进行,所以创建该静态实例时只有第一个静态变量k会赋值,后面的静态变量和静态语句块还都不存在;之后执行非静态代码,第一句非静态代码即是代码第7行的变量j赋值。这就解释了为什么第一条打印语句会是第7行的代码。同时这也解释了第二和第三条打印,第二条打印语句执行非静态代码,执行之后就调用构造函数创建实例对象s1。
同理,第4到6条打印语句是在创建静态实例对象s2时执行的。
在完成两个静态实例对象的创建后,下面要执行静态变量i的赋值,这就是第7条打印语句。后面还会对静态成员变量n赋值。之后是执行静态语句块,打印第8行语句。执行完静态代码部分后,接下来要执行非静态代码部分,按照写代码的前后顺序先为j赋值,然后执行非静态语句块,这就是第9和10行的打印语句。在执行完上面的所有步骤之后,开始执行类的构造函数创建对象,这就是第11行打印语句。
通过上面的分析我们发现:上述代码的执行顺序依旧符合一开始说明的java程序加载过程。只是由于有两个该类的静态实例变量,导致打印语句的复杂化。在这种情况下,打印过程类似于一个递归,每一次递归都按照标准的加载过程执行。
该代码一开始给人很多疑问,感觉运行过程中会抛出各种异常,但是代码却神奇地打印出了11条语句,的确让人吃惊。第一个疑问是该类内部有一个该类自身的静态对象,是否会导致循环递归。大家可以尝试一下,将代码第3或4行的static去掉,然后运行程序,就会提示StackOverflowError异常。为啥静态对象不会导致栈溢出,而非静态对象就会溢出?这是因为静态成员变量属于类所有,所有的类对象共享该静态成员变量,也即该静态成员变量只有一份,所以在递归的过程中,当发现正在创建该静态变量时,系统不会再去创建该变量,所以不会递归。但是如果是非静态对象,在递归的过程中,每次遇到该new语句都会再次创建一个新的对象,导致栈溢出。
该代码中另一个疑问是变量i的初值。在静态函数print中会打印i的值,但是在打印的时候变量i可能还没有定义(前6行打印语句都没有定义变量i)。程序居然也给通过了,这说明静态变量的声明会在初始化之前完成,并赋初值0。
java程序的加载过程的更多相关文章
- Java类的加载过程-重点!!
java类的加载过程有以下几步共同完成: 加载->连接->初始化.连接又分为验证.准备.解析 一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以 ...
- JAVA - 类的加载过程
JAVA - 类的加载过程 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象 ...
- 动态符号链接的细节 与 linux程序的加载过程
转: http://hi.baidu.com/clivestudio/item/4341015363058d3d32e0a952 值得玩味的一篇分析程序链接.装载.动态链接细节的好文档 导读: by ...
- IOS 应用程序启动加载过程(从点击图标到界面显示)
今天帮同事解决问题的时候发现,程序BUG是由加载过程引起的.所以当局部代码没有问题,但是程序一运行却总不是我们想要结果的时候,我们应该想想是不是因为我们忽略了试图加载过程的原因.下面我们用一个例子来简 ...
- Java 类的加载过程(阿里面试题)
问以下程序打印出什么内容: 问题及解析如下: /** * 加载方法不等于执行方法,初始化变量则会赋值 * 类加载顺序应为 加载静态方法-初始化静态变量-执行静态代码块 * 实例化时 先加载非静态方法- ...
- java中类的加载过程和对象的创建过程
1.类加载过程 首先,jvm在执行时,遇到一个新的类,会先去内存的方法区中去寻找该类的.class文件,如果找到了就直接运行,如果没有找到,则会去硬盘中去寻找该类的.class文件,并将该类文件加载到 ...
- Java类的加载过程与ClassLoader的理解及测试
当程序准备运行某个类,但该类还未被加载到内存中时,会经过以下三个步骤进行类的加载: 类的加载(Load)→类的连接(Link)→类的初始化(Initialize) 加载:类经过javac.exe编译的 ...
- java类的加载过程
1.类的加载顺序 (1)JVM在首次加载类时会对 静态初始化块.静态成员变量. 静态方法进行一次初始化. (2)只有在调用new方法时才会创建类的实例. (3)对象创建过程: 首先执行父类(如果有) ...
- iOS程序的加载过程
1.执行main函数2.执行UIApplicationMain函数1> 创建一个UIApplication对象(UIApplication是整个程序的象征)一个应用只有一个application ...
随机推荐
- CTR预估算法
GBRT(Gradient Boost Regression Tree)渐进梯度回归树,XGBoost是GBRT的一个工程实现 LR(Logistics Regression )逻辑回归 Spark ...
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
上一篇博客springMVC源码分析--ViewResolver视图解析器(一)中我们介绍了一些springMVC提供的很多视图解析器ViewResolver,在开发的一套springMVC系统中是可 ...
- Android使用shape制作圆形控件及添加弹跳动画
--------本来为作者原创,未经同意禁止转载 前言:我们在很多时候都需要在res/drawable文件夹下创建相应的xml文件来为控件添加一些样式效果,比如按钮按下时的按钮样式变化.或者指定按钮的 ...
- Findbug在项目中的运用--提高代码质量
FindBugs是一个静态分析工具,它检查类或者 JAR文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析 第一 手动安装 在Ec ...
- socket系列之客户端socket——Socket类
假设TCP套接字服务器端已经建立好并正在监听客户端的连接了,那么客户端就可以通过Socket类来发起连接.客户端发起一个连接请求后,就被动地在等待服务器的响应.这个类同样位于java.net包中,包含 ...
- Android View框架总结(七)View事件分发机制
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...
- Python pygame安装过程笔记
今天看到一个教程,是关于Python安装pygame模块的.觉得很好,拿来分享一下. 安装Python 额,这个小题貌似在这里很是多余啊.但是为了照顾到刚刚学习Python的童鞋,我还是多啰嗦两句吧. ...
- [ExtJS5学习笔记]第二十节 Extjs5配合数组的push方法,动态创建并加载组件
本文地址:http://blog.csdn.net/sushengmiyan/article/details/39226773 官方例子:http://docs.sencha.com/extjs/5. ...
- 关于weak
#define DECLARE_WEAK_SELF __typeof(&*self) __weak weakSelf = self #define DECLARE_STRONG_SELF __ ...
- Android项目开发填坑记-so文件引发的攻坚战
故事的最初 我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的so ...