Переменные области блока

Это скомпилирует

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). В чем причина, потому что невозможно объявить переменную в блоке с тем же именем, что и во внешнем блоке?

Ответ 1

Короткий ответ: так как язык Java определен в JLS §6.4.

Возможно, вы используете другие языки, которые разрешены так называемым изменением тени. Однако изобретатели языков 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;
}

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

Ответ 2

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

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

int a = 2;

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

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

Ответ 3

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

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

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

Ответ 5

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

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;   

   }
 }
}

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

Спасибо