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
}
}
}
Name shadowing is explained in JLS 6.4 Shadowing and Obscuring. I put the relevant parts of it for each of your examples.
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).
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
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.