1 成员变量
1.1 成员变量的分类
(1) 类变量(以static修饰)
- 生命周期:从该类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域与类的生存范围相同。
- 访问方式:类.类变量(推荐) 或者 实例.类变量(不推荐)
(2) 实例变量(不以static修饰)
- 生命周期:从该类的实例被创建时开始存在,直到系统完全销毁该实例,实例变量的作用域与对应实例的生存范围相同。
- 访问方式:实例.实例变量
1.2 成员变量的特点
(1) 成员变量无需显示初始化,系统在该类的准备阶段或者创建该类的实例时进行默认初始化。成员变量的默认初始化的赋值规则与数组动态初始化时数组元素的赋值规则完全相同。
(2) 一个类里不能定义两个同名的成员变量。
(3) Java允许成员变量和局部变量同名。如果方法里的局部变量和成员变量同名,局部变量会覆盖成员变量。如果需要在该方法里引用被覆盖的成员变量,可以使用this指针或类名作为调用者来限定访问的是成员变量而不是局部变量。
1.3 成员变量的初始化及内存中的运行机制
//
public class Person {
public String name;
public int age;
public static int eyeNum;
}
// 创建第一个Person对象
Person p1 = new Person();
// 创建第二个Person对象
Person p2 = new Person();
p1.name = "Amy";
p1.age = 16;
p2.name = "Tom";
p2.age = 15;
p1.eyeNum = 2;
p2.eyeNum = 3;
(1) 系统第一次使用Person类时系统会加载该类并初始化。在类的准备阶段,系统将会为类的类变量分配内存空间并指定默认初始值。此时系统内存中的存储示意图如下:
执行代码 Person p1 = new Person(); Person p2 = new Person(); 后,系统内存中的存储示意图如下:
(2) 执行代码 p1.name = “Amy”; p1.age = 16; p2.name = “Tom”; p2.age = 15; 后,系统内存中的存储示意图如下:
(3) 执行代码 p1.eyeNum = 2; 时,通过Person对象p1来修改Person的类变量,从图中也可以看出,Person对象根本没有保存类变量eyeNum。系统内存中的存储示意图如下:
(4) 执行代码 p2.eyeNum = 3; 时,通过Person对象p2来修改Person的类变量,系统内存中的存储示意图如下:
(5) 可以看出,通过类的实例访问类变量时,实质仍是通过类来访问类变量。当程序需要访问类变量时,建议使用类名作主调而不要使用对象作为主调。
2 局部变量
2.1 局部变量的分类
(1) 形参
- 在定义方法签名时定义的变量,作用域在整个方法内有效。
(2) 方法局部变量
- 在方法体内定义的局部变量,作用域为从定义该变量的地方有效,到该方法结束时失效。
(3) 代码块局部变量
- 在代码块内定义的局部变量,作用域为从定义该变量的地方有效,到该代码块结束时失效。
2.2 局部变量的特点
(1) 局部变量除了形参外,都必须显示初始化。形参的初始化在调用该方法时由系统完成,形参的值由方法的调用者负责指定。
(2) 一个方法里不能定义两个同名的方法局部变量,方法局部变量也不能与形参同名。
(3) 同一个方法中不同的代码块内的代码块局部变量可以同名。
(4) 后定义的方法局部变量可以与先定义的代码块局部变量同名。
2.3 局部变量的初始化及内存中的运行机制
局部变量在初始化之后系统才为其分配内存空间,它总是存储在其所在的方法栈内存中。栈内存中的变量无需系统垃圾回收,一般随着方法或代码块的结束而结束。局部变量所占的内存区通常都比较小。
3 变量使用规则
3.1 过度使用成员变量的缺点
(1) 增大了变量的生存时间,将导致更大的内存开销
(2) 扩大了变量的作用域,不利于提高程序的内聚性
3.2 使用规则
(1) 如果变量是用于描述某个类或某个对象的固有信息或特征属性的,通常应该定义为成员变量。
(2) 如果在某个类中需要以一个变量来保存类或实例的运行状态,通常应该定义为成员变量。
(3) 如果某个信息需要在类的多个方法之间共享,通常应该定义为成员变量。
(4) 使用局部变量时应尽可能的缩小局部变量的作用范围。局部变量的作用范围越小,它在内存中的停留时间越短,程序性能就越好。