1

I prepare for scjp exam and noticed surprising behaviour for me.

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)

    }
}

Always in my mind I kept following rule: I thought that all three variants is possible and inner definition would overlap external.

example shows that it is wrong rule.

Please clarify this situations and explain common rule for familiar situations.

P.S.

public class Test {
   int k;
    {
        int k;
        {
            int k;  //java: variable k is already defined in instance initializer of class Test
        }
    }
}
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710

1 Answers1

1

Name shadowing is explained in JLS 6.4 Shadowing and Obscuring. I put the relevant parts of it for each of your examples.

Local variables may hide fields

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

Since this piece of code is declared directly in a class, the first int f; defines a field, and the block is in fact an initializer block. The init block declares a local variable that hides the field's name within that init block. This is valid (but discouraged by a warning).

Local variables may not hide method parameters

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

This is not valid because, as the JLS 6.4 clearly states:

It is a compile-time error if the name of a formal parameter is redeclared as a local variable of the method or constructor

Local variables may not hide local variables (in the same "local space")

As the JLS 6.4 states:

It is a compile-time error if the name of a local variable v is redeclared as a local variable of the directly enclosing method, constructor, or initializer block within the scope of v

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

Here, the second statement tries to declare the same name, as another local variable of the same directly enclosing method, and within the scope of the former declaration. Not valid.

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
        }
    }
}

Here, the first statement declares a field. Then an init block starts, and a local variable is declared, obscuring the field's name (this 2nd declaration is valid). Now, a nested block is declared, with another local variable (3rd declaration) of the same directly enclosing init block and within the scope of the 2nd declaration. Not valid.

Joffrey
  • 32,348
  • 6
  • 68
  • 100
  • my P.S. corresponds rule **a local variable cannot hide another local variable.** ? – gstackoverflow May 09 '14 at 11:39
  • @gstackoverflow Exactly. Once you're inside the init block (the outer block) you declare a local variable to that block that can hide the field. **However**, within this block you declare a new block (inner block) that tries to declare another variable in the namespace of the init block (outer block). That is not allowed, because it is *local hiding local*. – Joffrey May 09 '14 at 11:43
  • @gstackoverflow I updated my answer with the exact JLS, this should be clear now ;-) – Joffrey May 09 '14 at 12:15
  • @gstackoverflow Thanks, but it was hard for me to explain why the local variable couldn't just hide the other local variable if declared in a little nested block. Now it's clear when the JLS states *directly enclosing method or init block*. – Joffrey May 09 '14 at 12:24