Следующий метод не работает, потому что внутренний блок объявляет переменную с тем же именем, что и во внешнем блоке. По-видимому, переменные принадлежат методу или классу, в котором они объявлены, а не блоку, в котором они объявлены, поэтому я не могу написать небольшой небольшой временный блок для отладки, который приводит к выталкиванию переменной из внешней области видимости в тень на мгновение:
void methodName() {
int i = 7;
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
}
Почти каждый язык с блочной областью видимости, который я когда-либо использовал, поддерживал это, включая тривиальные маленькие языки, для которых я писал интерпретаторы и компиляторы в школе. Perl может это делать, как Scheme и даже C. Даже PL / SQL поддерживает это!
В чем причина этого дизайнерского решения для Java?
Обновлено: как заметил кто-то, у Java есть область видимости блока. Как называется концепция, о которой я спрашиваю? Хотел бы я вспомнить больше из тех уроков по языковому дизайну. :)




Полагаю, это приводит к ошибкам, которые трудно обнаружить. Это похоже на C#.
Паскаль не поддерживает это, поскольку вы должны объявлять переменные над телом функции.
Я считаю, что причина в том, что в большинстве случаев это происходит не намеренно, а из-за ошибки программирования или логики.
в таком тривиальном примере, как ваш, это очевидно, но в большом блоке кода случайное повторное объявление переменной может быть неочевидным.
ETA: это также может быть связано с обработкой исключений в java. Я думал, что часть этого вопроса обсуждалась в вопросе, связанном с тем, почему переменные, объявленные в разделе try, не доступны в областях catch / finally.
Потому что писатели нередко делают это намеренно, а затем полностью облаживаются, забывая, что теперь есть две переменные с одинаковыми именами. Они изменяют имя внутренней переменной, но оставляют код, который использует эту переменную, который теперь непреднамеренно использует ранее затененную переменную. Это приводит к тому, что программа все еще компилируется, но выполняется с ошибками.
Точно так же нередко случайное затенение переменных и изменение поведения программы. Незаметное затенение существующей переменной может изменить программу так же легко, как и отключение затенения переменной, как я упоминал выше.
В разрешении этой слежки так мало пользы, что они исключили ее как слишком опасную. Серьезно, просто назовите новую переменную как-нибудь еще, и проблема исчезнет.
Я бы пошел дальше, чтобы сказать, что нет никаких причин для этого вообще. Нет ничего, что можно сделать с теневыми переменными, чего нельзя было бы обойтись без них.
Единственный раз, когда они мне нравятся, это аргументы конструктора, поэтому я могу сделать "this.foo = foo". Изменение имен ради конструкторов некрасиво, некрасиво, некрасиво. "фу "," фу", мля.
Ну, строго говоря, Java делает имеет объявления переменных с блочной областью видимости; так что это ошибка:
void methodName() {
for (int j = 0; j < 10; j++) {
int i = j * 2;
}
System.out.println(i); // error
}
Потому что «i» не существует вне блока for.
Проблема в том, что Java не позволяет вам создавать переменную с тем же именем, что и другая переменная, которая была объявлена во внешнем блоке того же метода. Как говорили другие люди, якобы это было сделано для предотвращения ошибок, которые трудно идентифицировать.
Основное предположение в этом вопросе неверно.
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++;
}
Я не могу понять, почему вы хотите, чтобы область видимости вел себя иначе. Было бы невозможно определить, какой i вы имеете в виду внутри цикла for, и я готов поспорить, что в 99,999% случаев вы хотите ссылаться на i внутри метода.
Я хочу сослаться на i внутри метода. Вот как работают C, Perl и Scheme. Так почему же из-за этого невозможно определить, что я хочу?
Другая причина: если бы такое объявление переменных было разрешено, людям был бы нужен (нужен?) способ доступа к переменным внешнего блока. может быть добавлено что-то вроде "внешнего" ключевого слова:
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;
}
}
}
Впервые я увидел это в разделе «Обработка исключений». Там я ничего об этом не думал; Я просто предположил, что реализация препятствовала этому по какой-то внутренней причине. Только когда я заметил, что это повлияло на простые блоки, я действительно начал задаваться вопросом «почему»?