Foreach с именем переменной, равным имени поля
Нашел интересную вещь, скомпилировав следующий фрагмент кода:
1 class A {
2
3 private B line;
4
5 public void foo() {
6 for (Integer line : line.getElements()) {
7
8 }
9 }
10 }
11
12 class B {
13
14 List<Integer> getElements() {
15 return null; // doesn't matter
16 }
17 }
Обратите внимание на строку 6: мы видим, что имя переменной равно имени поля. IntelliJ Idea 11 игнорирует это и думает, что здесь нет никаких проблем. Но java-компилятор говорит мне, что "строка не имеет метода getElements". Итак, два вопроса:
- Должен ли я сообщать об ошибке в Idea?
- Почему сообщение об ошибке с Java такое? Разве это не способно обнаружить ошибку? Какой механизм работает здесь? Затмение переменной поля?
Ответы
Ответ 1
Это может быть ошибка в компиляторе Java, который вы используете. Согласно Спецификация языка Java (раздел 14.14.2), область действия переменной в расширенном выражении for
представляет собой содержащуюся инструкцию. (Кажется, это исключает итеративное или массивное выражение справа от :
.)
Вы можете обойти проблему, используя this.line.getElements()
.
ИЗМЕНИТЬ
Просто для ударов, я представил это как отчет об ошибке для Sun. Мы увидим, считают ли инженеры Java ошибкой в JLS или в javac (или если у них есть другое объяснение). Идентификатор ошибки 7139681, хотя он не будет отправлен во внешнюю базу данных в течение нескольких дней.
Ответ 2
Если вы объявите локальную переменную (это то, что вы сделали) с тем же именем, что и поле, то вы можете получить доступ к переменной поля как this.name
.
for (Integer line : this.line.getElements()) {
}
Ответ 3
Когда вы используете IntelliJ, он автоматически анализирует все файлы. Однако с javac
он может не скомпилировать все программы, esp, если они были скомпилированы ранее.
Скажем, у вас есть класс B (без getElements()) и вы его скомпилируете. Позже вы добавите метод и только скомпилируете A, он будет жаловаться, что B не имеет этого метода, потому что в последний раз, когда вы его скомпилировали, такого метода не было.
Способом удаления всех файлов *.class перед компиляцией или использованием инструмента построения, такого как maven.