2013-12-10 3 views
11

Это будет компилироватьБлок переменных область применения

class X 
{ 
    public static void main(String args[]) 
    { 
     { 
      int a = 2; 
     } 
     { 
      int a = 3; 
     }  
    } 
} 

Это не

class X 
{ 
    public static void main(String args[]) 
    { 

     int a = 2; 

     { 
      int a = 3; 
     }  
    } 
} 

Я ожидал, как компилировать (может быть, это путь C работает?). В чем причина, потому что невозможно объявить переменную в блоке с тем же именем, что и во внешнем блоке?

ответ

11

Короткий ответ: Потому что это способ языка Java определяется в JLS §6.4.

Возможно использование на других языках так называемого variable shadowing. Однако изобретатели языков Java считали, что это была неудобная функция, которую они не хотели на своем языке:

Это ограничение помогает обнаружить некоторые непонятные ошибки.

Однако найти затенения в другом месте в Java, как утверждают авторы, в том же разделе JLS:

Подобное ограничение на затенение членов местных переменных было судить непрактично, так как дополнение члена в суперклассе может привести к тому, что подклассы должны будут переименовать локальные переменные. Связанные соображения делают ограничения на затенение локальных переменных на членами вложенных классов или на затенение локальных переменных локальными переменными, объявленными внутри вложенных классов, также непривлекательными.

Это означает, что на практике, что следующий код является законным:

class A { 
    int x = 0; 
    void m() { 
    int x = 10; // Shadows this.x 
    } 
} 

Как описывают авторы, разрешаются теневым переменным экземпляр, объявляя локальный переменный метод с тем же именем, так как из возможность кого-то расширение функциональности A в один прекрасный день, когда вы не могли больше компилировать класс B если затенение было незаконным:

class B extends A { 
    void m() { 
    int x = 10; // Shadows A.this.x if A declares x 
    } 
} 

Если рассматривать язык как C, где затенение разрешено, вы можете найти неловкое такой код:

int x; 
int main() 
{ 
    { 
    int x = 0; 
    { 
     extern int x; 
     x = 1; 
    } 
    printf("%d\n", x); // prints 0 
    } 
    printf("%d\n", x); // prints 1 
    return 0; 
} 

Эта программа не так легко следовать, и, возможно, поэтому не дают ожидаемый результат, благодаря переменной затенение.

3

Потому что во втором случае a известен внутри статического блока, поэтому вы пытаетесь сделать redeclare it. Компилятор не позволяет это сделать:

public static void main(String args[]) { 
    { 
     int a = 2; //a is known only here 
    }    //a will be freed 
    { 
     int a = 3; //you can declare it again here 
    }  
} 
4

Java не позволяет вам иметь две переменные с одинаковым именем в пределах друг от друга.

В вашем втором случае:

int a = 2; 

{ 
    // the outer 'a' is still in scope 
    int a = 3; // so this is a redeclare <-- nooo! 
} 

Однако в первом случае каждый a содержится в его собственной области, так что все хорошо.

+0

Осторожнее с утверждением 'Java не позволяет вам иметь две переменные с одинаковыми именами в рамках одной another.' Это справедливо только для [локальных переменных, методов, конструкторов и параметров исключения] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.3) –

+0

@SotiriosDelimanolis Как эта ссылка вы цитируете, поддерживая ваше заявление? – flow2k

+1

@ flow2k Это не так. Он просто определяет локальные переменные и параметры. Область определяется [здесь] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.3). –

0
public static void main(String args[]) 
{ 
    int a = 2; // I know a 
    // I know a 
    { 
     // I know a 
     int a = 3; // There can be only one a! 
    }  
} 

В приведенном выше примере вы объявили a в вас метод main(). Из декларации до конца метода объявляется a. В этом случае вы не можете обновить a в своем кодовом блоке.

Ниже вы объявляете a в блоке. Это только известно.

public static void main(String args[]) 
{ 
    { 
     int a = 2; // I know a 
     // I know a 
    } 
    // Who is a? 
    { 

     int a = 3; // I know a! 
    }  
} 
-4

В Java все локальные переменные будут храниться в стеке. Так что, если и писать

class X 
{ 
public static void main(String args[]) 
{ 
    int a = 2; // At this point var 'a' is stored on Stack 
    { 
     /* 
     Now as the prev. 'main method is not yet complete so var 'a' is still present on the Stack. So at this point compiler will give error "a is already defined in main(java.lang.String[])" 
     */ 
     int a = 3; 

    } 
} 
} 

Надеется, что это помочь вам

Благодаря

+2

Это просто неправильно. Скомпилированный код не знает имена локальных переменных, он знает только индексы. Кроме того, переменные не обязательно оба лежат в стеке одновременно. Каждый кадр метода имеет как стек операнда, так и массив локальных переменных. * В Java все локальные переменные будут храниться на Stack *, поэтому неточно. –

Смежные вопросы