1

我为 scjp 考试做准备,并注意到对我来说令人惊讶的行为。

public class Test {
    int k;
    {
        int k; // it is valid variant
    }
    public static void main(String[] args) {
        int kk;
        {
            int kk; // NOT VALID.java: variable kk is already defined in method main(java.lang.String[])
        }
    }
    public void method (int var){
           int var;//NOT VALID.java: variable var is already defined in method method(int)

    }
}

在我的脑海中,我始终遵循以下规则:我认为所有三种变体都是可能的,并且内部定义会与外部重叠。

例子表明这是错误的规则。

请澄清这种情况并解释熟悉情况的常见规则。

附言

public class Test {
   int k;
    {
        int k;
        {
            int k;  //java: variable k is already defined in instance initializer of class Test
        }
    }
}
4

1 回答 1

1

JLS 6.4 Shadowing and Obscuring中解释了名称阴影。我为您的每个示例都放置了它的相关部分。

局部变量可能隐藏字段

public class Test {
    int f; // field declaration
    { // init block
        int f; // WARNING: Local variable f is hiding a field from type Test 
    }
}

由于这段代码是直接在类中声明的,所以首先int f;定义了一个字段,该块实际上是一个初始化块。init 块声明了一个局部变量,该变量在该 init 块中隐藏了字段的名称。这是有效的(但因警告而气馁)。

局部变量不能隐藏方法参数

public void method (int param){
    int param; // NOT VALID
}

这是无效的,因为正如JLS 6.4明确指出的那样:

如果将形式参数的名称重新声明为方法或构造函数的局部变量,则会出现编译时错误

局部变量不能隐藏局部变量(在同一个“局部空间”中)

正如JLS 6.4所述:

如果局部变量 v 的名称在 v 的范围内被重新声明为直接封闭的方法、构造函数或初始化块的局部变量,则会出现编译时错误

public static void main(String[] args) {
    int local;
    {
        int local; // NOT VALID: local declaration in same method
    }
}

在这里,第二个语句尝试将同名声明为同一个直接封闭方法的另一个局部变量,并且在前一个声明的范围内。无效。

public class Test {
    int f; // field declaration
    { // init block
        int f; // VALID: local declaration hiding field
        { // nested local block
            int f; // NOT VALID: local declaration in same init block
        }
    }
}

在这里,第一条语句声明了一个字段。然后启动一个 init 块,并声明一个局部变量,隐藏字段的名称(这第二个声明是有效的)。现在,声明了一个嵌套块,其中另一个局部变量(第 3 个声明)直接包含在 init 块中,并且在第 2 个声明的范围内。无效。

于 2014-05-09T11:25:03.780 回答