Почему в Java нет объявлений переменных с блочной областью видимости?

StackOverflow https://stackoverflow.com/questions/141140

  •  02-07-2019
  •  | 
  •  

Вопрос

Следующий метод не работает, потому что внутренний блок объявляет переменную с тем же именем, что и во внешнем блоке.Очевидно, переменные принадлежат методу или классу, в котором они объявлены, а не блоку, в котором они объявлены, поэтому я не могу написать короткий временный блок для отладки, который на мгновение отодвигает переменную во внешней области видимости в тень:

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

Почти каждый язык с блочной областью действия, который я когда-либо использовал, поддерживал это, включая тривиальные маленькие языки, для которых я писал интерпретаторы и компиляторы в школе.Perl может это сделать, как и Scheme, и даже C.Даже PL / SQL поддерживает это!

Каково обоснование такого дизайнерского решения для Java?

Редактировать:как кто-то указал, Java действительно имеет область видимости блоков.Как называется концепция, о которой я спрашиваю?Жаль, что я не могу вспомнить больше из тех уроков языкового дизайна.:)

Это было полезно?

Решение

Я полагаю, что логическое обоснование заключается в том, что в большинстве случаев это не намеренно, это программная или логическая ошибка.

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

ETA:это также может быть связано с обработкой исключений в java.я думал, что часть этого вопроса обсуждалась в вопросе, связанном с тем, почему переменные, объявленные в разделе try, были недоступны в областях catch / finally.

Другие советы

Ну, строго говоря, Java делает иметь объявления переменных с блочной областью видимости;так что это ошибка:

void methodName() {
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
  System.out.println(i); // error
}

Потому что "я" не существует вне блока for.

Проблема в том, что Java не позволяет вам создать переменную с тем же именем, что и у другой переменной, которая была объявлена во внешнем блоке того же метода.Как говорили другие люди, предположительно, это было сделано для предотвращения ошибок, которые трудно идентифицировать.

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

Аналогично, нередки случаи случайного затенения переменных и изменения поведения программы.Неосознанное затенение существующей переменной может изменить программу так же легко, как и удаление затенения переменной, как я упоминал выше.

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

Я думаю, это приводит к ошибкам, которые трудно обнаружить.То же самое происходит и в C #.

Pascal не поддерживает это, так как вы должны объявлять переменные над телом функции.

Лежащее в основе этого вопроса предположение неверно.

Java делает иметь область действия на уровне блока.Но у него также есть иерархия областей применения, вот почему вы можете ссылаться i в пределах for цикл, но не j вне цикла for.

public void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    i = j * 2;
  }

  //this would cause a compilation error!
  j++;
}

Я ни за что в жизни не смогу понять, почему вы хотели бы, чтобы scoping вел себя как-то по-другому.Было бы невозможно определить, какой именно i вы имели в виду внутри цикла for, и я бы поспорил, что шансы составляют 99,999% случаев, когда вы хотите обратиться к i внутри метода.

еще одна причина:если бы такого рода объявление переменных было разрешено, люди хотели бы (нуждались?) способ доступа к переменным внешнего блока.может быть, будет добавлено что-то вроде ключевого слова "outer":

void methodName() {
    int i = 7;
    for (int j = 0; j < 10; j++) {
        int i = outer.i * 2;
        if(i > 10) {
            int i = outer.outer.i * 2 + outer.i;
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top