我宣布了private static double fd
,然后我再次在main()内宣布double fd
。为什么我可以成功编译并运行它?
public class HelloWorld {
private static double fd = 1.0;
public static void main(String[] args){
System.out.println(fd); //1.0
double fd = 2.0;
System.out.println(fd); //2.0
}
}
这不是语法错误(虽然它可能会导致逻辑错误,一个错误)。编译器将编译此代码而不会抱怨。 double fd的第二个声明为main方法创建一个局部变量。此变量的范围以其声明开始,并在块的结尾处结束(与所有局部变量一样)。所以下一个语句使用局部变量,而不是实例变量。
方法返回后,局部变量将不再保留值。实例变量不会被更改。
提示:将语句看作从他们自己的位置向上看,以找到他们的每个变量。如果他们未能在自己的方法中找到变量,他们可以向任何方向看他们的“玻璃盒子”。
对实例变量和局部变量使用相同的名称几乎总是错误的。但它不是语法错误,因此编译器不会警告您。
来自JLS Scope of a Declaration部分:
声明的范围是程序的区域,声明声明的实体可以使用简单的名称引用该区域,前提是它没有被遮蔽。
来自JLS Shadowing部分:
某些声明可能会在其作用域的一部分中被另一个同名声明所遮蔽,在这种情况下,简单名称不能用于引用声明的实体。
这意味着您不能使用简单名称(df
)来引用类级别的df
变量,因为它被本地df
变量遮蔽。但是仍然有两个变量,你可以使用带有类名的静态变量:
public static void main(String[] args){
System.out.println(fd); //1.0
double fd = 2.0;
System.out.println(fd); //2.0
System.out.println(HelloWorld.fd);
}
变量fd是函数作用域,想想它,编译器首先检查离它最近的范围,然后如果它找到那里它试图检查全局范围,如果它在本地范围内找到了什么,它将打印出来,或者否则继续检查其他范围。