您的位置:首页 > 编程语言 > Java开发

java程序执行过程及静态块、非静态块执行顺序

2015-07-31 14:31 513 查看

1、java类加载介绍(此部分内容来源于网络):

1.1、类加载过程

java类的加载过程分以下几个步骤:



1)装载:查找并加载类的二进制数据;
2)链接:
验证:确保被加载类的正确性;
准备:为类的静态变量分配内存,并将其初始化为默认值;
解析:把类中的符号引用转换为直接引用;
3)初始化:为类的静态变量赋予正确的初始值;

1.2、类初始化时机

当出现以下六种情况是,会执行类的初始化过程:

1)创建类的实例,也就是new一个对象
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射,Class.forName("com.mysql.jdbc.Driver")
5)初始化一个类的子类(会首先初始化子类的父类)
6)JVM启动时标明的启动类,即文件名和类名相同的那个类

1.3、类初始化步骤

1)如果这个类还没有被加载和链接,那先进行加载和链接
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
3)加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句

2、实例解析

从总体上来说java类中的代码是按如下顺序执行的:



public class LoadTest {
//构造器
private LoadTest() {
System.out.println("staticI="+(++staticI)+"; i="+(++i));
}
//全局静态变量
static int staticI = 10;
//全局变量
int i = 20;
//静态实例1
private static LoadTest instance1 = new LoadTest();
//静态代码块
static {
staticI = 100;
}
//静态实例2
private static LoadTest instance2 = new LoadTest();
//代码块
{
i = 200;
}
//main方法
public static void main(String[] args) {
LoadTest t = new LoadTest();
}
}
上述代码执行完后staticI的值是多少?会打印出什么样的信息?下面我们来一步步解析。

通过执行java LoadTest命令可以启动程序,并执行LoadTest中的代码,其中的过程大致可以分为以下几步:
1)启动jvm,由Bootstrap
classloader加载java程序运行需要用到的基础类库,并启动app
classloader。
2)类加载器app
classloader到classpath目录下加载LoadTest.class文件到jvm内存区域的方法区中,并在堆中生成一个LoadTest的java.lang.Class实例。此过程完成了前面提到的类加载过程中的前两个步骤即装载和连接,此时类变量staticI=0,instance1=null,instance2=null(连接阶段会为类变量分配内存空间并赋予默认值)。
3)执行LoadTest中的main方法,这意味着此类为一个启动类会执行初始化过程为静态变量赋予正确的值,及执行静态代码块,接下来分析一下初始化的具体过程:

①首先执行第7行:
static int staticI = 10;
将静态变量staticI值修改为10
②进入到第11行:

private static LoadTest instance1 = new LoadTest();

为静态变量instance1实例化一个LoadTest类型的对象,在创建对象之前先会执行第9行及19到21行这段代码,将实例变量i赋值为200,然后再执行构造函数打印输出:staticI=11;
i=201

③进入13行执行静态代码块:
static {
staticI = 100;
}

将staticI的值修改为100
④进入17行:
private static LoadTest instance2 = new LoadTest();

为静态变量instance2实例化一个LoadTest类型的对象,同instance1一样,实例化过程中也需要先执行第9行及19到21行这段代码,将实例变量i赋值为200,然后再执行构造函数打印输出:staticI=101;
i=201
至此整个初始化过程结束。
4)执行main方法体中的代码,再次实例化一个LoadTest对象,经过初始化过程后staticI的值变成了101,所以在main方法中实例化对象时,构造函数中应该打印出:staticI=102;
i=201

所以最终的打印结果为:
staticI=11; i=201
staticI=101; i=201
staticI=102; i=201
staticI的值为102。

3、总结

1)java程序遵循先加载再使用的原则。
2)静态全局变量(类变量)、静态代码块中的代码只会执行一次,这个执行过程发生在类初始化阶段。并且静态全局变量是所有类实例共享的,在一个实例中修改了静态变量的值,其他实例看到的将是修改后的值。
3)非静态全局变量(实例变量)、非静态代码块在每次实例化对象时都会执行,并且其先于构造器被执行。非静态全局变量不是所有类实例共享的,一个类修改了它的实例变量的值,不会影响到该类其他实例变量。
4)静态全局变量、静态代码块遵循从上到下依次执行的原则,越前面的代码越先被执行,非静态全局变量、非静态代码块也是如此。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: