在JAVA语言里,根据定义变量位置的不同,可以将变量分成两大类:成员变量和局部变量。二者的运行机制存在较大差异。
类变量从该类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域与这个类的生存范围相同;
而实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个实例,实例变量的作用域与对应实例的生存范围相同。
正是基于这个原因,可以把类变量和实例变量统称为成员变量。
其中类变量可以理解为类成员变量,它作为类本身的一个成员,与类本身共存亡;实例变量则可以理解为实例成员变量,它作为实例的一个成员与实例共存亡。
只要类存在,类就可以访问类变量 -- 类.类变量
只要实例存在,实例就可以访问实例变量 -- 实例.实例变量
当然实例也可以访问类变量。但是需要注意的是因为实例不拥有类变量,所以通过实例来访问类变量进行操作,实际上是对类变量进行操作,当有其他实例来访问类变量时,访问的类变量是被对象访问操作过的类变量。
成员变量无需显示初始化,只要为一个类定义了类变量或实例变量,系统就会在这个类的准备阶段或创建该类的实例时进行默认初始化。
局部变量根据定义形式的不同,又可以分为如下三种:
一个变量只在一对{ }中起作用。
Java允许局部变量和成员变量同名,如果方法中局部变量和成员变量同名,局部变量就会覆盖成员变量,如果需要在这个方法中引用被覆盖成员变量,则可使用this(对于实例变量)或类名(对于类变量)作为调用者来限定访问成员变量。
接下来以下面代码来举例说明成员变量的初始化和内存中的运行机制
public class Person {
public static int num;
public String name;
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.num = 2;
p2.num = 3;
p1.name = "张三";
p2.name = "李四";
}
}
当程序执行Person p1 = new Person();时,如果这行代码是第一次使用Person类,则系统通常会在第一次使用Person类时加载这个类,并初始化这个类,在类的准备阶段,系统将会为该类的类变量分配内存空间,并指定默认初始值。当Person类初始化完成后,系统内存中的存储示意图如下图所示。
可以看出,当Person类初始化完成后,系统将在堆内存中为Person分配一块内存空间,实际上是创建了一个类对象,在这块内存区里包含了保存num类变量的内存,并设置num的默认初始值为0。
系统接着创建了一个Person对象,并把这个Person对象赋给p1变量,Person对象包含了名为name的实例变量,实例变量是在创建实例时分配内存空间并指定初始值的。当创建了第一个person对象后,系统内存中的存储示意图如下图所示。
从上图可以看出num不属于对象,它属于类,所以创建第一个对象时并不需要为num分配内存空间,系统只是为name分配了内存空间,并指定初始值为null。
创建第二个对象p2时,由于在创建第一个对象时已经对类进行了初始化,所以在创建p2时对类进行初始化,对象的创建过程与第一个对象的创建过程没有什么区别。
第二个对象创建完成后,成员变量如上图所示在内存中存储。
当程序需要访问类变量时,尽量使用类来作为主调,不要使用对象作为主调,这个可以避免产生歧义。
原文链接:
Java面向对象——成员变量和局部变量(成员变量和局部变量的初始化和内存运行机制&变量的使用规则)
https://www.cnblogs.com/newveg/p/6591435.html