public class Test {
int a;
static int b = 123;
final static int c;
void init(){
int d;
}
public static void main(String[] args) {
int e;
System.out.println(e);
}
}
上面的Test类中定义了5个不同类型的变量,那么这些变量是如何进行初始化的呢?要先声明一点,上述代码是有问题的,编译不通过。
首先给大家明确一下Java中关于变量的类型,Java有三种变量类型,类变量,实例变量,局部变量。局部变量的生命周期与声明局部变量方法的声明周期相同,仅当方法被调用时,创建局部变量,方法执行结束,销毁局部变量。
类变量的初始化分为两个阶段。第一次是在类加载的准备阶段。准备阶段会正式为类变量分配内存并设置类变量的初始值。如果类变量是基本数据类型,初始值为其对应初值,如果为对象类型,初始值为null,执行下面代码,结果为null,0
public class Test {
static Integer b;
static int c;
public static void main(String[] args) {
System.out.println(b+","+c);
}
}
准备阶段还有一种例外情况,如果类变量同时被final关键字修饰,那么准备阶段就会直接将变量赋值。下面代码中,c的值会在准备阶段直接赋值为123。
public class Test {
final static int c = 123;
public static void main(String[] args) {
System.out.println(c);
}
}
对于没有被final关键字修饰的类变量,其赋值过程是在类加载过程中的初始化阶段。实例变量则会在对象实例化时随着对象一起被分配在Java堆中。而类变量随类加载过程中被分配给堆上的逻辑划分——方法区。
回到文章最开头的例子,实例变量a和类变量b的分配初始化如上所述,常量c在准备阶段会被直接赋值,而此处并没有对c赋值,故编译报错。局部变量d随着方法init的调用在栈上分配,局部变量e的定义没有问题,但未赋值的局部变量无法被访问。
其实这里有个小细节,一个局部变量如果创建后从未被使用过,编译器会自动优化忽略掉这个变量的定义,具体可查看编译后的class文件。