java变量之成员变量和局部变量以及它们的运行机制

 Java语言根据变量定义位置的不同,将变量分为成员变量和局部变量。成员变量指的是定义在类中(方法外)的变量,局部变量指的是定义在方法中的变量。同时成员变量以是否用static修饰分为类变量和实例变量。局部变量根据定义位置的不同分为形参,方法局部变量,代码块局部变量。如图1所示。

图1

    变量的命名除了应该遵守命名规范以外还应该要见文知意,能够通过名字明白该变量的用途,这样有利于后续代码的修改,提高效率。

    成员变量:成员变量分为类变量和实例变量,类变量从该类的准备阶段开始存在,直至该类被系统销毁,类变量仅被类所拥有,成员变量不拥有类变量;实例变量则从该类的实例被创建时存在直至实例被销毁。访问类变量的方式有两种:类.类变量和实例.类变量,但是因为实例不拥有类变量,所以其实访问的还是类的变量,因此当使用实例对类变量进行修改时,该类变量会受到影响,其他对象访问此变量也会看到变化。而访问实例变量仅有一种方式,实例.实例变量。

    局部变量:局部变量分为形参(整个方法内有效),方法局部变量(从定义开始到方法结束有效),代码块局部变量(从定义开始到代码块结束有效)。局部变量从被初始化时开始存在直至方法结束。

下面将成员变量和临时变量的初始化和运行机制以例子方式进行说明:

    成员变量:

    我写了一个Dog类,里面包含两个成员变量,类变量nose和实例变量name。如图2所示。

图2

     在Test类的main方法中,我开始对Dog类进行一系列操作。代码如图3所示。

 图3

    Dog dog = new Dog(),在我进行这一步操作时,若系统第一次使用Dog类,那么系统需要加载这个类,并初始化类。在类的准备阶段,系统为类分配空间并初始化类变量默认值。如图4所示。

 图4

     类加载完毕后,系统将创建dog变量,分配内存空间并初始化实例变量,此时堆栈内存情况如图5所示。

 图5

     dog.name = “小黑狗”,执行这句代码后,我为dog对象的name变量赋值小黑狗,此时内存情况如图6所示。

图6

    执行Dog dog2 = new Dog();此时系统中已有Dog类,无需再加载Dog类,此时创建Dog对象dog2,系统为dog2对象分配内存,初始化dog2的name变量为null。此时内存情况如图7所示。

图7

    dog2.name = “小白狗”;执行这句代码为dog2对象name赋值,情况与dog1一致。

    dog2.nose = 1,此时虽然通过dog2对象改变了nose的值,但是因为nose属于类本身,所以类变量nose值被改变,此时用dog1去访问nose将得到值1.如图8所示。

图8

    综上所述:java成员变量分为类变量和实例变量,类变量在类被加载时进行初始化,实例变量在对象实例化时进行初始化,类变量属于类本身,被所有实例所共享,实例变量属于实例私有。

    局部变量:局部变量定义之后,必须经过显示初始化之后才能使用,系统不会为局部变量执行初始化操作。这意味着定义局部变量之后,系统并未为这个变量分配内存空间,直到等程序为这个变量赋初始值时,系统才会为局部变量分配内存。局部变量不属于任何类或实例,它保存在所在方法的内存栈中,如果局部变量时基本类型,则对应内存直接保存值,若为引用类型,则保存地址,通过该地址引用到该变量实际的对象或数组。

    因为局部变量存在方法栈中,方法结束即被销毁,所以不需要垃圾回收机制。其生命周期从初始化(不是定义时)开始,到方法结束时被销毁。

     总结:

     成员变量是无需显示初始化的,系统在类的准备阶段(初始化类变量)或者创建该类的实例时(初始化实例变量)进行默认初始化。而局部变量必须进行显示初始化,否则不能访问。

    成员变量和局部变量可以重名,若重名,在方法中需要访问成员变量可用this.变量名的方式。(注:this在构造方法中表示当前正在创建的对象,在普通方法中表示调用该方法的对象)。

    根据不同变量类型的作用域不同,应该合理选择使用何种变量。比如可以使用局部变量的却使用的成员变量,成员变量存储在堆中,这就扩大了变量的生存时间和作用域。扩大生存时间导致更大的内存开销,扩大作用域导致不利于提高程序的内聚性。

参考--------《java疯狂讲义》

原文地址:https://www.cnblogs.com/lin0/p/12398675.html