持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
3 成员变量和局部变量
3.1 成员变量和局部变量
成员变量被分为类Field和实例Field两种,定义Field时没有static修饰的就是实例Field,有static修饰的就是类Field。
提示:正如前面提到的,Java允许通过实例来访问static修饰的Field本身就是一个错误,因此读者以后看到通过实例来访问static Field的情形,都可以将它替换成通过类本身来访问static Field的情形,这样程序的可读性、明确性都会大大提高。
与成员变量不同的是,局部变量除了形参之外,都必须显式初始化。也就是说,必须先给方法局部变量和代码块局部变量指定初始值,否则不可以访问它们
Java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,局部变量会覆盖成员变量,如果需要在这个方法里引用被覆盖的成员变量,则可使用this(对于实例Field)或类名(对于类Field)作为调用者来限定访问成员变量。
3.2 成员变量的初始化和内存中的运行机制
//创建第一个Person对象
Person p1=new Person();
//创建第二个Person对象
Person p2=new Person();
//分别为两个Person对象的name Field赋值
p1.name="张三";
p2.name="孙悟空";
//分别为两个Person对象的eyeNum Field赋值
p1.eyeNum=2;
p2.eyeNum=3;
当程序执行第一行代码Person p1=new Person();时,如果这行代码是第一次使用Person类,则系统通常会在第一次使用Person类时加载这个类,并初始化这个类。
系统接着创建了一个Person对象,并把这个Person对象赋给p1变量,Person对象里包含了名为name的实例Field,实例Field是在创建实例时分配内存空间并指定初始值的
eyeNum类Field并不属于Person对象,它是属于Person类的,所以创建第一个Person对象时并不需要为eyeNum类Field分配内存,系统只是为name实例Field分配了内存空间,并指定默认初始值:null。
3.3 局部变量的初始化和内存中的运行机制
局部变量定义后,必须经过显式初始化后才能使用,系统不会为局部变量执行初始化。这意味着定义局部变量后,系统并未为这个变量分配内存空间,直到等到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。 与成员变量不同,局部变量不属于任何类或实例,因此它总是保存在其所在方法的栈内存中。
3.4 变量的使用规则
如果仅就程序的运行结果来看,大部分时候都可以直接使用类Field或者实例Field来解决问题,无须使用局部变量。但实际上这种做法相当错误,因为当我们定义一个成员变量时,成员变量将被放置到堆内存中,成员变量的作用域将扩大到类存在范围或者对象存在范围,这种范围的扩大有两个害处:
增大了变量的生存时间,这将导致更大的内存开销; 扩大了变量的作用域,这不利于提高程序的内聚性。
public class ScopeTest3
{
public static void main(String[] args)
{
//定义一个代码块局部变量作为循环变量
for (int i=0 ; i < 10 ; i++)
{
System.out.println("Hello");
}
}
}
第三个程序最符合软件开发规范:对于一个循环变量而言,只需要它在循环体内有效,因此只需要把这个变量放在循环体内(也就是在代码块内定义),从而保证这个变量的作用域仅在该代码块内。