我刚开始学习Java。我有一些愚蠢的问题。我真的不明白为什么在这种情况下:
int j = 5;
for (int j = 0; j < 10; j++) {
// do sth
}
我的编译器说:the variable j is already defined in the scope
。
为什么这一秒j
有问题?我认为它应该简单地掩盖第一个。
我刚开始学习Java。我有一些愚蠢的问题。我真的不明白为什么在这种情况下:
int j = 5;
for (int j = 0; j < 10; j++) {
// do sth
}
我的编译器说:the variable j is already defined in the scope
。
为什么这一秒j
有问题?我认为它应该简单地掩盖第一个。
问题是您要声明变量j
两次:一次在for
循环外,一次在循环内。只需删除上面的行for
,您就可以开始了。
局部变量没有被遮蔽——也许你已经想到了字段(但这与你在这里的不同)。
一个更简单但类似的场景是:
int i = 0;
{
int i = 2;
}
所以你有两个i
变量。当您引用时,您指的是哪一个i
?
Java 编译器在这里不允许“遮蔽”。定义是模棱两可的,编译器正在努力警告您这一点。
有关阴影和模糊的规则,请查看Java 语言规范,第 6.4 节
他们甚至提供了相同的示例:
由于将标识符声明为方法、构造函数或初始化程序块的局部变量不得出现在同名参数或局部变量的范围内,因此以下程序会发生编译时错误:
class Test1 {
public static void main(String[] args) {
int i;
for (int i = 0; i < 10; i++)
System.out.println(i);
}
}
此限制有助于检测一些原本非常晦涩的错误。对局部变量隐藏成员的类似限制被认为是不切实际的,因为在超类中添加成员可能会导致子类必须重命名局部变量。相关考虑使得限制嵌套类的成员对局部变量的遮蔽,或对嵌套类中声明的局部变量对局部变量的遮蔽也没有吸引力。
就这样吧。如果允许您i
在 for 循环中声明变量,那么您将如何引用在循环之前声明的局部变量 ?您不能使用任何限定名称来执行此操作,简单名称将引用 for 循环变量。这就是为什么它是不允许的。i
for
该行为如 JLS 中所列。来自JLS - 第 6.4 节:
局部变量(第 14.4 节)、形参(第 8.4.1 节)、异常参数(第 14.20 节)和本地类(第 14.3 节)只能使用简单名称(第 6.2 节)而不是限定名称( §6.6)。
有些声明不允许在局部变量、形参、异常参数或局部类声明的范围内,因为仅使用简单名称就无法区分声明的实体。
并来自JLS - 第 6.3 节:
块中局部变量声明的范围(第 14.4 节)是声明出现的块的其余部分,从它自己的初始化程序开始,并在局部变量声明语句的右侧包括任何进一步的声明符。
强调我的。
同样,在 JLS 第 6.4 节中,指定在同一范围内重新声明局部变量将导致编译时错误:
如果局部变量 v 的名称在 v 的范围内被重新声明为直接封闭的方法、构造函数或初始化程序块的局部变量,则会出现编译时错误;或作为 v 范围内直接封闭方法、构造函数或初始化块的 try 语句中的 catch 子句的异常参数;或作为 v 范围内直接封闭方法、构造函数或初始化块的 try-with-resources 语句中的资源。
Cause this is a duplicate local variable problem, You already define "j" variable before. Try this:
int i = 5;
for (int j = 0; j < 10; j++) {
// do sth
}
仅当变量之一是方法字段而另一个变量是局部变量时,才会发生阴影。在您的情况下,两者都是局部变量,因此它们不能相互影响。
如果它们以相同的方式共享范围,则不能有两个同名的局部变量,就像不能有两个同名的字段一样。
int j = 5; // this j is visible to whole method
for (int j = 0; j < 10; j++) {
// so still j is visible to this for loop and you can use it
// but you can't initialize it again
// do sth
}
j
您已两次声明变量。重写你的代码如下:
for (int j = 0; j < 10; j++) {
// do sth
}
或者
int j;
for (j = 0; j < 10; j++) {
// do sth
}