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

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

1.1、类加载过程

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

1)装载:查找并加载类的二进制数据;

2)链接:

      验证:确保被加载类的正确性;

      准备:为类的静态变量分配内存,并将其初始化为默认值;

      解析:把类中的符号引用转换为直接引用;

3)初始化:为类的静态变量赋予正确的初始值;

1.2、类初始化时机

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

1)创建类的实例,也就是new一个对象

2)访问某个类或接口的静态变量,或者对该静态变量赋值

3)调用类的静态方法

4)反射,Class.forName("com.mysql.jdbc.Driver")

5)初始化一个类的子类(会首先初始化子类的父类)

6JVM启动时标明的启动类,即文件名和类名相同的那个类

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行及1921行这段代码,将实例变量i赋值为200,然后再执行构造函数打印输出:staticI=11; i=201
         ③进入13行执行静态代码块:
        static {
	      staticI = 100;
	}
     staticI 的值修改为 100
         ④进入17行:
         private static LoadTest instance2 = new LoadTest();
                为静态变量instance2实例化一个LoadTest类型的对象,同instance1一样,实例化过程中也需要先执行第9行及1921行这段代码,将实例变量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)静态全局变量、静态代码块遵循从上到下依次执行的原则,越前面的代码越先被执行,非静态全局变量、非静态代码块也是如此。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值