Java中的变量作用域

大多数程序设计语言都提供了“作用域”(Scope)的概念。

在Java中,作用域决定了变量的“可见性”和“生存时间”。Java中的作用域是有花括号{}来决定的。

先来看一段代码:

1
2
3
4
5
6
7
8
public class Scope{
static {
int a = 1;
{//作用域起点
int a = 2;//这里会报错,因为外部已经定义了一个a的变量
}//作用域终点
}
}

上面的例子中,由于int a = 1这行代码已经在最外部的作用域中声明a变量,所以在内部的作用域是不可以再重新声明a了,只能拿到a这个变量来进行使用,这是Java中强制规定的,而在C和C++中是允许的,因为Java的设计者认为这样会造成混淆。

再来看一个例子:

1
2
3
4
5
6
7
8
public class Scope{
static {
{
int a = 2;
}
int a = 1;//这样是允许的
}
}

看到有什么不同了吗?我们把int a = 1这行代码放到了内部作用域的下方了,此时是允许的。由于int a = 2是定义在作用域里面,当超过作用域时,这块的内存空间会自动从中移除,并且同一块作用域的变量的“可见性”是只能在当前作用域及它的子作用域可见。由于int a = 1已经超出了该作用域,所以可以再次声明一个a变量。

再来看一个例子来理解下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Scope{

private static String name = "a";

public static void func() {
System.out.println(name);
name = "b";
{
String name = "c";
System.out.println(name);
{
name = "d";
}
System.out.println(name);
}
System.out.println(name);
for (int i = 0; ; i++) {
System.out.println(i);
break;
}
int i = 1;
System.out.println(i);
name = "e";
System.out.println(name);
}

public static void main(String[] args) {
func();
}

}

执行结果:

1
2
3
4
5
6
7
a
c
d
b
0
1
e

Java对象不具备与基本类型数据一样的存在时间。用new关键字创建一个Java对象的时候,它会超出作用域的范围之外。

对象的作用域
1
2
3
4
5
public class Scope{
void func() {
String str = new String();
}
}

上面的 str 变量会在作用域外消失,但是 new String() 出来的对象是不存在中的,它存在中,并且不会随着作用域而消失。它随后会由Java垃圾回收器进行释放,垃圾回收器会查找用new所创建的所有对象,并判断其中哪些对象不再被变量引用,从而释放内存以便新的对象存储。

总结

在同一作用域范围下的成员变量和局部变量是可以变量名相同的,在同一个作用域下和子作用域的局部变量则不允许变量名相同,在方法中使用变量的时候假如不指明使用成员变量还是局部变量,那么默认的就是使用成员变量,但是如果在方法中重新定义了一个和成员变量相同的局部变量,那么就会默认使用局部变量,并且在该作用域下的该变量都是使用局部变量,一旦超出该作用域,如果不指定,默认还是使用成员变量的。