变量的可见性
一般的书里会将变量的作用范围叫做变量的作用域,或者scope of variables,这个说法并不直观,本节将用变量的可见性和可用性来代替。不过本质和变量的作用域是一致的。
1. 代码的归属关系
Java里一行代码肯定得归属于一个代码块(import
、package
和定义类的语句不在讨论范围),一个类里的代码归属和层级关系可以用下图描述。这里我们把靠外的block叫外部结构体,靠内的叫内部结构体。(一个结构体可以看作是由{}
包围起来的一个代码块)
Fig. 1. 单个Java类的代码结构
- 上图有一个最外部的结构体:一个类;
- 该类有两个内部结构体:方法1和方法2;
- 方法1又包含两个
for/while/if
构建的内部结构体; - 第一个
for/while/if
结构体里,还可能内嵌其他for/while/if
结构体。
定义:
单个类里变量的可见性/可用性:在一个地方定义的一个变量,可以被哪些结构体看到并使用。
2. 变量的可见性/可用性规则
总则
一个结构内定义的变量,只能被该结构体及其内部结构体看见并使用。
或者
==一个变量,只能被其所在花括号{ }及内部花括号的语句识别。==
例1. Example1.java
public class Example1 {
private static int classVar = 0;
public static void main(String[] args) { // main方法是Example1类的一个内部结构体
classVar++; // main方法可以看见classVar并修改它的值
System.out.println("classVar's value is changed by inner main method to " + classVar);
int mainMethodVar = 0;
if (true) {
classVar++; // if代码块可以看见其外层Example1类的变量classVar
mainMethodVar++; // if代码块可以看见其外层main方法的变量mainMethodVar
System.out.println("classVar is changed by inner if-block to " + classVar);
System.out.println("mainMethodVar is changed by inner if-block to " + mainMethodVar);
for (int i = 0; i < 5; i++) {
// 外层结构体的变量(类变量和main方法的变量)甚至可以被if代码块的内部for代码块看见并使用。
classVar++;
mainMethodVar++;
}
System.out.println("classVar = " + classVar + ", mainMethodVar = " + mainMethodVar);
}
}
}
分则(1)
- 一个在内部结构体内定义的变量,不能被其外部结构体看见。
例2.Example2.java
注:这段代码存在两个错误,无法编译执行。
public class Example2 {
public static void main(String[] args) {
if(true) {
int ifVar = 0; // if代码块内的变量,不能被外部的main方法看见
}
System.out.println(ifVar); // 不能识别ifVar,系统报错
for(int i = 0; i < 2; i++) { // 这里的i是for循环体里定义的变量,不能被外部main方法看见
}
System.out.println(i); // 不能识别i,系统报错
}
}
上面的代码中,
ifVar
是在if
代码块里定义的,不能被其外层的main
方法看见;i
是在for
循环代码块中定义,不能被其外层的main
方法看见;- 以上两处System.out.println()方法都会报错:
i/ifVar cannot be resolved to a variable
,表明无法识别两个变量
分则(2)
- 一个类的两个方法是同级关系,一个方法内定义的变量不能被另一个方法识别。
- 方法的参数属于方法的私有变量 (在方法内部定义的),不能被其外层结构体识别。
例3.Example3.java
注:这段代码存在错误,无法编译执行。
public class Example3 {
public static void methodB(int parameter) {
int methodBVar = 0;
// parameter 和methodBVar都是methodB的变量,无法被main方法识别
if (true) { //methodB的参数和变量,可以被其内部代码块识别
parameter = 1;
methodBVar = 1;
}
}
public static void main(String[] args) {
// 尝试在main方法里使用methodB的参数和变量
parameter = 1; // 无法识别,系统报错
methodBVar = 1; // 无法识别,系统报错
}
}
分则(3)
- if - else if - else结构中,各个代码块是平行和相互独立的,每个代码块内部定义的变量无法被其他两个并行代码块识别。
如
if (关系表达式){
代码块1;
} else if {
代码块2;
} else {
代码块3;
}
代码块1、2、3是平行和相互独立的,代码块1中定义变量,无法被2、3代码块识别,以此类推。
简单总结: