1.首先我们要引入一个函数驱动的概念
在C/C++中的程序,都要以函数驱动的形式执行,即从一个函数的内部的执行流程,经过函数调用跳转到被调用函数内部执行另一个流程。当被调函数执行结束时,需要返回结果并回至函数调用发生处的下一句继续处理。(另一篇文章将详细介绍函数驱动)
我们知道程序需要经过编译和链接,程序代码最终链接成为二进制的exe文件;
在代码载入内存的时候就会自动执行的代码,被称为静态/全局代码。
即代码首先载入执行“静态和全局代码”,然后从main函数开始执行。
下面给出一个C++中包含全局对象、静态对象的例子:
class A
{
private:
char str[100];
public:
A(char *p);
}global("全局对象global"); //1
void main()
{
A localobj("局部对象localobj");//4
....
}
static A globalstatic("全局静态对象");//2
A global2("全局对象2")://3
运行顺序为:1—>2—>3—>4
我们已经明白main里面的最后执行,但可能会疑惑为什么1会先执行,而不是静态的全局对象2先执行?
2.这里我们就要了解C++中全局变量、静态全局变量、局部变量:
全局变量:不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在多文件文件中,通过 extern 全局变量名的声明,就可以使用全局变量。
静态全局变量:显式被static修饰的全局变量。和全局变量在存储方式上是一致的,都储存在数据段,编译阶段分配内存空间,在程序结束时释放。但是,对于多文件的程序来说静态全局变量只在定义该变量的源文件内有效,也就是我们常说的它具有隐身属性。
局部变量:函数中定义的变量是该函数的局部变量。它们在其他函数的语句中是不可见的。即作用域只在该函数内
即带static的全局变量的作用:在多文件中,在声明它的整个文件都是可见的,而在文件之外是不可见的。(本文只考虑单文件)
即带不带static对执行顺序没什么改变,main外全局变量顺序执行
而在Java中static与C++的左右有很大不同
3.Java类装载
3.1单类执行顺序
先看代码: 带static的却首先执行 这是为什么呢?这里涉及的是类装载以及代码块的知识
Class Test()
{
Class B
{
class B(){}//3 再执行构造函数
{ int a = 10;}//2 然后执行构造代码块
static{ int b 0;}//1 首先执行静态代码块
static B global();//4 最后执行全局对象
}
}
我们都知道Java代码有三个阶段,分别是源代码阶段,类加载阶段,运行阶段。
类装载其实就指的就是类加载阶段的Java代码在JVM中的加载过程。大致可以分为三个阶段,分别是加载,连接,初始化。
代码中的代码块指的是什么呢?
代码块:在Java中使用{}括起来的代码。
根据其位置和声明的不同,可以分为局部代码块、静态代码块、构造代码块。
局部代码块:局部位置,用于限定局部变量的生命周期。
构造代码块:在类的成员位置,用{} 括起来,每实例化一次对象,执行一次里面的代码,且多个构造代码块,按照顺序执行构造代码块
静态代码块:在类的成员位置,用static{} 只有在类加载的时候,才会执行,且只执行一次,且由于是在类加载时才会执行,所以先于main方法前执行
所以执行顺序为:静态代码块>构造代码块>构造方法>全局对象
3.2多类执行顺序
先上结论:类C中调用类B,如果有带static的,先执行,其他按顺序执行
如下代码
Class Test()
{
Class B
{
Class B(){} //4
{ int a = 10;} //3
static{ int b = 10;} //2
}
Class C
{
B global() = new .... //5
static B global2() = new ...//1
}
}
在C中调用B,C中static先执行,即1初始化了B,进入B,B类的执行顺序就是单类的执行顺序,B类执行完毕,回到C类,执行C类的剩下语句。