Java|Java面向对象之各种变量详解( 四 )



下面开始解读:
当程序执行第一行代码 Person p1 = new Person(); 时
如果这行代码是第一次使用 Person 类.
则系统会加载并初始化这个类.
在类的准备阶段.
系统将会为该类的类变量分配内存空间并指定默认初始值.
当 Person 类初始化完成后 系统内存中的存储示意图如下:

从上图可以看出.
当 Person 类初始化完成后.
系统将在堆内存中为 Person 类分配一块内存区.
在这块内存区中 包含了 保存 eyeNum 类变量的内存.
并设置 eyeNum 的默认初始值为: 0
系统接着创建了一个 Person 对象.
并把这个 Person 对象赋给 p1 变量.
Person 对象里包含了名为 name 的实例变量.
实例变量是在创建实例时分配内存空间并指定初始值的.
当创建了第一个 Person 对象后 系统内存中的存储示意图如下:

从上图可以看出 eyeNum 类变量并不属于 Person 对象.
它是属于 Person 类的.
所以创建第一个 Person 对象时并不需要为 eyeNum 类变量分配内存(废话…)
系统只为 name 实例变量分配了内存空间.
并指定默认初始值: null
接着执行 Person p2 = new Person();
代码创建第二个 Person 对象.
此时因为 Person 类已经存在于堆内存了.
所以不需要对 Person 类进行初始化(废话…Java 会那么傻么…)
创建第二个 Person 对象 与 创建第一个 Person 对象并没有什么不同.
当程序执行 p1.name = “孙悟空”; 时
将为 p1 的 name 实例变量赋值.
也就是让堆内存中的 name 指向 “孙悟空” 字符串.
我们之前说过 字符串也是一种引用变量. 所以你懂的.
执行完成后 两个 Person 对象在内存中的存储示意图如下:

从上图可以看出 name 实例变量是属于单个 Person 实例的.
因此 修改第一个 Person 对象的 name 实例变量时仅仅与 p1 对象有关.
与 Person 类和其它 Person 对象没有任何关联.
同理 修改第二个 Person 对象 p2 的 name 实例变量时 也与 Person 类和其它 Person 对象无关.
直到执行 p1.eyeNum = 2 时
此时呢 就是犯大忌了. 你拿 对象来操作类变量了. 不过为了教学演示 我拿自己当典型.
从我们看过的图当中 可以知道.
Person 的对象根本没有保存 eyeNum 这个变量.
通过 p1 访问的 eyeNum 类变量.
其实还是 Person 类的 eyeNum 类变量.
因此 此时修改的是 Person 类的 eyeNum 类变量.
修改成功后 内存中的存储示意图如下:

从上图可以看出.
不管通过哪个 Person 实例来访问 eyeNum 类变量.
它们访问的其实都是同一块内存.
所以就再次提醒你.
当程序需要访问 类变量时.
尽量使用类作为主调 而不要使用对象作为主调.
这样可以避免歧义 提高程序的可读性.
局部变量的初始化和内存中的运行机制局部变量定义后.
必需经过显式初始化后才能使用.
系统不会为局部变量执行初始化.
这意味着定义局部变量之后系统并未为这个变量分配内存控件.
直到等程序为这个变量赋初始值时.
系统才会为局部变量分配内存并将初始值保存到这块内存中去.
与成员变量不同局部变量不属于任何类或实例.
因此它总是保存在其所在的方法的栈内存中.
如果局部变量是基本类型变量则直接把这个变量的值保存在该变量对应的内存中.
如果局部变量是引用类型的变量则这个变量里存放的就是地址.
通过该地址引用到该变量实际引用的对象或数组.
变量的使用规则对于新手来说.
什么时候使用类变量?