首先,在java中变量可以分为:局部变量和成员变量。
局部变量:形参、方法内定义的变量并在方法内对其显示初始化、代码块内定义的变量并在代码块内对其初始化等。
成员变量:非静态变量(实例变量)和静态变量(类变量)。
局部变量没什么可说的。这里主要是讲JVM怎样对成员变量分配内存及其初始化。
何为静态变量?这个很简单----带有static 修饰的成员变量。同理非静态变量就是没带static的。使用了static修饰的成员变量是类变量,顾名思义,属于类本身。而在同一个JVM内,每个类也只对应一个Class对象。所以在同一个JVM下,通常情况下只会为类变量分配一块内存空间。反之,实例变量属于类的实例。所以一个类可以创建多少个对象就需要分配多少块内存。
到这里,最明白的一点就是:在同一个JVM中每个类变量只对应一块内存,而实例变量对应的不止一块。
那类变量和实例变量时怎么初始化的呢?
先举个例子吧:
public class Var extends Basic{
int a=8;
{
System.out.println("在块中初始化b");
b=88;
}
int b;
static int c=888;
public void printVar(){
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("c="+c);
}
public Var(){
}
public static void main(String[] args) {
new Var();
}
}
class Basic{
public Basic(){
printVar();
}
public void printVar(){
}
}
执行上面程序你会发现结果是:
a=0
b=0
c=888
在块中初始化b
很奇怪吧?
假如你设计几个断点用eclipse类单步执行方法也就是debug下,你就会发现在变量框下的this对象会出现两个变量a和b,而没有c.并且初始值都为0。
我们先看这个程序怎么执行的。先找到入口点main方法,通过new一个Var对象。Var类继承Basic类,所以向上执行Basic的构造方法public Basic()。在构造方法中又调用了printVar(),此处的调用其实调用子类Var中的printVar方法。所以就执行了子类中的printVar方法将a,b,c的值打印出来。
那为什么是这个结果呢?
首先从类变量说,很容易理解。在还没执行new Var();前就被赋值为888了。所以结果中又c的值为888;
那a,b的值怎么来的呢?
其实前面说过,用eclipse对程序debug时,就是先定义这两个变量,初始默认值为0;这时候你就估计能知道结果中的0其实是默认初始值。明明在语句中给其赋值了啊。
其实所有的实例变量的赋值都是在构造方法下执行的。所以在上面的代码中,无论你是在定义时赋值还是在块中赋值,还是在构造方法中赋值。其实最终都是在构造方法下赋值的。在执行Var构造方法前要执行其继承的Basic方法的构造方法。
所以你就会注意到定义在块中的执行语句的打印值在最后。
所以导致了最后,Var构造方法还没给a,b变量赋真正的值,a,b的值就被输出了。
上面的程序还有个小的细节,那就是块中的变量的赋值在代码中的顺序先于变量的定义。其实带有赋值变量的块放在变量定义的前后都是可以的。但对变量所赋的值是按代码中的顺序的。假如把上面程序中b的赋值改为如下:
{
System.out.println("在块中初始化b");
b=88;
}
int b=99;
public Var(){
System.out.println(b);
}
你会发现结果是:
a=0
b=0
c=888
在块中初始化b
99
所以变量在块中赋值和在块赋值只与其在代码中的顺序有关。
理解好了这个程序,肯定会对变量在内存中的初始化有一个进一步的了解。