变量的可见性

一般的书里会将变量的作用范围叫做变量的作用域,或者scope of variables,这个说法并不直观,本节将用变量的可见性可用性来代替。不过本质和变量的作用域是一致的。

1. 代码的归属关系

Java里一行代码肯定得归属于一个代码块(importpackage和定义类的语句不在讨论范围),一个类里的代码归属和层级关系可以用下图描述。这里我们把靠外的block叫外部结构体,靠内的叫内部结构体。(一个结构体可以看作是由{}包围起来的一个代码块)

code structure

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代码块识别,以此类推。


简单总结:

外层能被内层看见,而内层不能被外层看见。