Подтвердить что ты не робот

В чем разница между каждым и традиционным для цикла в Java с точки зрения затенения?

Это код, который у меня есть:

class HelloWorld {

    char[] foo = {'a', 'b'};

    // This will compile
    void foo() {
        for (char foo : foo) {
        }
    }

    // This will not compile
    void bar() {
        for (char foo = 0; foo < foo.length; foo++) {
        }
    }
}

Как получилось, что foo компилирует, но компилирует bar с:

Error: char cannot be dereferenced

В чем разница между двумя объявлениями цикла, которые делают цикл в компиляции foo, но бар не работает?

4b9b3361

Ответ 1

Мы можем видеть разницу, глядя на JLS§14.14.2 описание того, как улучшенный for работает при обработке массива:

Усиленный оператор for эквивалентен основному выражению формы:

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
    {VariableModifier} TargetType Identifier = #a[#i];
    Statement
}

Обратите внимание, как переменная объявляется внутри тела цикла, а не заголовка цикла. То есть ваша функция foo выглядит следующим образом:

void foo() {
    { // Freestanding block for scope, though not really needed as `foo` has
      // nothing else in it
        char[] a = foo;       // T[] #a = Expression;
        for (int i = 0; i < a.length; i++) {
            char foo = a[i];  // {VariableModifier} TargetType Identifier = #a[#i];
        }
    }
}

Вот почему вы избегаете теневого копирования в расширенном for, а не в традиционном for, которому необходимо получить доступ к исходному массиву (чтобы получить его length, чтобы получить запись для i и т.д.).

Подробнее о расширенном цикле for в Как работает цикл Java для каждого цикла? и его ответы.

Ответ 2

Спецификация языка Java определяет область действия двух char foo по-разному:

Область локальной переменной, объявленной в части ForInit базовой for (§14.14.1) включает в себя все следующее:

  • Свой собственный инициализатор
  • Любые другие деклараторы справа в части ForInit оператора for
  • Элементы выражения и ForUpdate оператора for
  • Заявление

Область локальной переменной, объявленной в части FormalParameter расширенный оператор for (§14.14.2) - это содержащееся выражение.

(JLS 8, раздел 6.3)

Это прекрасно объясняет ваше наблюдаемое поведение: локальный foo находится в области действия в элементе управления основного цикла for (везде справа от его объявления), и поэтому он тенерирует другой foo там, но в расширенном цикле for его область действия является только оператором цикла - она ​​не находится в области где-либо в предложении управления циклом.