成员变量的初始化和内存中的运行机制

来源:互联网 发布:windows fix it 下载 编辑:程序博客网 时间:2024/05/17 09:20
成员变量被分为类变量和实例变量两种,定义成员变量时没有static修饰的就是实例变量,有static修饰的就是类变量。其中类变量从该类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域与这个类的生存范围相同;而实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个实例,实例变量的作用域与对应实例的生存范围相同。
可以把类变量和实例变量统称为成员变量,其中类变量可以理解为类成员变量,它作为类本身的一个成员,与类本身共存亡;实例变量则可理解为实例成员变量,它作为实例的一个成员,与实例共存亡。
只要类存在,程序就可以访问该类的类变量。在程序中访问类变量通过如下语法:
类.类变量
只要实例存在,程序就可以访问该实例的实例变量。在程序中访问实例变量通过如下语法:
实例.实例变量
当然,类变量也可以让该类的实例来访问。通过实例来访问类变量的语法如下:
实例.类变量

但由于这个实例并不拥有这个类变量,因此它访问的并不是这个实例的变量,依然是访问它对应类的类变量。也就是说,如果通过一个实例修改了类变量的值,由于这个类变量并不属于它,而是属于它对应的类。因此,修改的依然是类的类变量,与通过该类来修改类变量的结果完全相同,这会导致该类的其他实例来访问这个类变量时也将获得这个被修改过的值。

class Person{        public String name;        public static int eyeNum;}public class PersonTest {        public static void main(String[] args) {                System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);                Person p = new Person();                System.out.println("p变量的name变量值是: " + p.name + " p对象的eyeNum变量值是: " + p.eyeNum);                p.name = "孙悟空";                p.eyeNum = 2;                System.out.println("p变量的name变量值是: " + p.name + " p对象的eyeNum变量值是: " + p.eyeNum);                System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);                Person p2 = new Person();                p2.name = "张三";                p2.eyeNum = 3;                                Person p3 = new Person();                p3.name = "李四";                p2.eyeNum = 4;                System.out.println("p1对象的eyeNum类变量值:" + p.eyeNum);                System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);                System.out.println("p2对象的eyeNum类变量值:" + p2.eyeNum);                System.out.println("p1对象的name类变量值:" + p.name);                System.out.println("p2对象的name类变量值:" + p2.name);                System.out.println("p3对象的name类变量值:" + p3.name);                        }}
outputs:
Person的eyeNum类变量值:0p变量的name变量值是: null p对象的eyeNum变量值是: 0p变量的name变量值是: 孙悟空 p对象的eyeNum变量值是: 2Person的eyeNum类变量值:2p1对象的eyeNum类变量值:4Person的eyeNum类变量值:4p2对象的eyeNum类变量值:4p1对象的name类变量值:孙悟空p3对象的name类变量值:李四p2对象的name类变量值:张三

当Person类初始化完成后,系统将在堆内存中为Person类分配一块内存区,在这块内存区里包含了保存eyeNum类变量的内存,并设置eyeNum的默认初始值:0.
系统接着创建了一个Person对象,并把这个Person对象赋给p变量,Person对象里包含了名为name的实例变量,实例变量是在创建实例时分配内存空间并指定初始值的。
eyeNum类变量并不属于Person对象,它是属于Person类的,所以创建第一个Person对象时并不需要为eyeNum类变量分配内存,系统只是为name实例变量分配了内存空间,并指定默认初始值:null.
接着执行Person p2 = new Person();代码创建第二个Person 对象,此时因为Person 类已经存在于对内存中了,所以不再需要对Person 类进行初始化。创建第二个Person 对象与创建第一个Person 对象并没有什么不同。
name实例变量是属于单个Person实例的,因此修改第一个Person对象的name实例变量时仅仅与该对象有关,与Person类和其他Person对象没有任何关系。同样,修改第二个Person对象的name实例变量时,也与Person类和其他Person对象无关。
执行p.eyeNum = 2;代码时,此时通过Person对象来修改Person的类变量,Person对象根本没有保存eyeNum这个变量,通过p访问的eyeNum类变量,其实还是Person类的eyeNum类变量。因此,此时修改的是Person类的eyeNum类变量。
当通过p来访问类变量时,实际上访问的是Person类的eyeNum类变量。事实上,所有的Person实例访问eyeNum类变量时都将访问到Person类的eyeNum类变量,本质其实还是通过Person类来访问eyeNum类变量时,他们所访问的是同一块内存。因此,建议当程序需要访问类变量时,尽量使用类作为主调,而不要使用对象作为主调,这样可以避免程序产生歧义,提高程序的可读性。



0 0