成员变量和局部变量
在Java语言中,根据定义变量位置的不同,可以将变量分成两大类:
- 成员变量
- 局部变量
其中类变量从该类的准备阶段起开始存在,类变量的作用域与这个类的生存范围相同-----与类本身共存亡;
实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个实例,实例变量的作用域与对应实例的生存范围相同-----与实例共存亡;
Person.java:
public class Person
{
//定义一个实例属性
public String name;
//定义一个类属性
public static int eyeNum;
}
TestPerson.java:
public class TestPerson
{
public static void main(String[] args)
{
//Person类已经加载,则eyeNum变量起作用了,输出0
System.out.println("Person的eyeNum类属性值:" + Person.eyeNum);
//创建Person对象
Person p = new Person();
//通过Person对象的引用p来访问Person对象name实例属性
//并通过实例访问eyeNum类属性
System.out.println("p变量的name属性值是:" + p.name
+ " p对象的eyeNum属性值是:" + p.eyeNum);
//直接为name实例属性赋值
p.name = "孙悟空";
//通过p访问eyeNum类属性,依然是访问Person的eyeNum属性
p.eyeNum = 2;
//再次通过Person对象来访问name实例属性和eyeNum类属性
System.out.println("p变量的name属性值是:" + p.name
+ " p对象的eyeNum属性值是:" + p.eyeNum);
//前面通过p修改了Person的eyeNum属性,此处的Person.eyeNum将输出2
System.out.println("Person的eyeNum类属性值:" + Person.eyeNum);
Person p2 = new Person();
//p2访问的eyeNum类属性依然引用Person类的,因此依然输出2
System.out.println("p2对象的eyeNum类属性值:" + p2.eyeNum);
}
}
成员变量无须显式初始化,系统会在这个类的准备阶段或创建该类的实例时进行默认初始化,成员变量默认初始化时的赋值规则与数组动态初始化时数组元素的赋值规则完全相同;
局部变量根据定义形式的不同,又可以被分为如下三种:
- 形参:在定义方法签名时定义的变量,形参的作用域在整个方法内有效;
- 方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量的地方生效,到该方法结束时失效;
- 代码块局部变量:在代码块中定义的局部变量,这个局部变量的作用域从定义该变量的地方生效,到该代码块结束时失效;
与成员变量的不同,局部变量除了形参之外,都必须显式初始化:
定义代码块局部变量:
public class TestBlock
{
public static void main(String[] args)
{
{
//定义一个代码块局部变量a
int a;
//下面代码将出现错误,因为a变量还未初始化
//System.out.println("代码块局部变量a的值:" + a);
//为a变量赋初始值,也就是进行初始化
a = 5;
System.out.println("代码块局部变量a的值:" + a);
}
//下面试图访问的a变量并不存在
//System.out.println(a);
}
}
代码中可以看出,只要离开了代码块局部变量所在的代码块,这个局部变量就立即被销毁,变为不可见;
方法局部变量:
public class TestMethodLocalVariable
{
public static void main(String[] args)
{
//定义一个方法局部变量a
int a;
//下面代码将出现错误,因为a变量还未初始化
//System.out.println("方法局部变量a的值:" + a);
//为a变量赋初始值,也就是进行初始化
a = 5;
System.out.println("方法局部变量a的值:" + a);
}
}
Java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,局部变量会覆盖成员变量,如果需要在这个方法里引用被覆盖的成员变量,则可使用this(对于实例变量)或类名(对于类变量)作为调用者来限定访问成员变量;
public class TestVariableOverride
{
//定义一个name实例属性
private String name = "李刚";
//定义一个price类属性
private static double price = 78.0;
//主方法,程序的入口
public static void main(String[] args)
{
//方法里的局部变量,局部变量覆盖成员变量
int price = 65;
//直接访问price变量,将输出price局部变量的值:65
System.out.println(price);
//使用类名来作为price变量的限定,将输出price类属性的值:78.0
System.out.println(TestVariableOverride.price);
//运行info方法
new TestVariableOverride().info();
}
public void info()
{
//方法里的局部变量,局部变量覆盖成员变量
String name = "孙悟空";
//直接访问name变量,将输出name局部变量的值:"孙悟空"
System.out.println(name);
//使用this来作为name变量的限定,将输出price实例属性的值:"李刚"
System.out.println(this.name);
}
}
成员变量的初始化和内存中的运行机制
当系统加载类或创建该类的实例时,系统自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值;
以Person.java为例:
//创建第一个Person对象
Person p1 = new Person();
//创建第二个Person对象
Person p2 = new Person();
//分别为两个Person对象的name实例变量赋值
p1.name = "张三";
p2.name = "孙悟空";
//分别为两个Person对象的eyeNum 类变量赋值
p1.eyeNum = 2;
p2.eyeNum = 3;
从图5.11中可以看出,eyeNum类变量并不属于Person对象,它是属于Person类的,所以创建第一个Person对象时并不需要为eyeNum类变量分配内存,系统只是为name实例变量分配了内存空间,并指定默认初始值:null;
局部变量的初始化和内存中的运行机制
局部变量定义后,必须经过显式初始化后才能使用,系统不会为局部变量执行初始化;
与成员变量不同,局部变量不属于任何类或实例,因此它总是保存在其所在方法的栈内存中;
书籍:疯狂Java讲义
学习所做的笔记,特此记录下来