[Java] Почему локальные переменные должны быть final в этой ситуации?

enochka1145

У Б. Экеля в его "Thinking in Java" приводится такой код - ещё один пример, чтобы читатель проникнулся необходимостью использовать ключевое слово synchronized.
public class AlwaysEven {
private int i;
public void next { i++; i++; }
public int getValue { return i; }
public static void main(String[] args) {
final AlwaysEven ae = new AlwaysEven;
new Thread("Watcher") {
public void run {
while(true) {
int val = ae.getValue;
if(val % 2 != 0) {
System.out.println(val);
System.exit(0);
}
}
}
}.start;
while(true)
ae.next;
}
}
Одного я не понимаю - зачем нужно слово final (в 6-й строке сверху)?

bastii

Final переменные доступны из анонимного класса как примере. Не final нельзя было бы использовать в run. Хотя я в этом не уверен, сам никогда такой фишкой не пользовался.

enochka1145

Если убрать final, программа не будет компилироваться, т. к. это нарушение
Java Language Specification
...
8.1.2 Inner Classes and Enclosing Instances
...
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final, and must be definitely assigned (§16) before the body of the inner class.
Я только не могу понять, зачем такое правило. Типа, яйца курицу не учат?

bastii

А ты попробуй представить как это все дело реализуют (ведь это все синтаксические фокусы). Тогда станет понятно

enochka1145

Ну посуди сам. У экземпляра внутреннего класса всегда есть ссылка на экземпляр внешнего - того, кто его создал. Он может читать внешние данные. Так почему он не может их писать?

boikodima1

ae - локальная переменная и не является частью внешнего класса

Dasar

потому что тело внешней функции может завершиться и уничтожить переменную ae раньше, чем будет происходить запись в эту переменную.

Marinavo_0507

В некоторых других языках это ничему не мешает.

Dasar

согласен. просто похоже, что они пошли по самому простому пути реализации
ps
> пошли по самому простому пути реализации
Именно, такого рода проблемы я имею ввиду, когда говорю, что Java-у sun почти не развивает.

enochka1145

ОК, а как final этому препятствует?
(...я и сам ищу, но пока ничего не нашёл...)

Dasar

afaik, final гарантирует, что переменная больше меняться не будет.
Поэтому переменную можно раскопировать по всем контекстам.

enochka1145

Речь идёт о локальных переменных (спасибо -у, что обратил внимание). А они даже в Java создаются в стеке. После первой же } стек, надо думать, возвращается в то состояние, в каком он был до соответствующей {. Вот я и не пойму: а причём тут final?

Dasar

> стек, надо думать, возвращается в то состояние, в каком он был до соответствующей
Что произойдет, если внутренняя функция в этот момент запишет по адресу разрушенной переменной какое-либо значение?
или прочитает из разрушенной переменной значение еще раз?

enochka1145

Извини, я, наверно, туплю. Но я не вижу здесь принципиальной разницы между записью и чтением. И то, и другое - ошибка (если переменная разрушена).

Dasar

> И то, и другое - ошибка (если переменная разрушена).
Поможет ли нам, если мы скопируем значение оригинальной переменной в какое-нибудь другое место при старте внутренней фукнции, и дальше уже внутренняя фукнция будет лазить в это другое место?
Какие при этом возникают проблемы?
Помогает ли эти проблемы решить слово final?

enochka1145

Речь идёт лишь о локальных переменных. "Другие места" (например, элемент данных внешнего класса) проблем не вызывают.

enochka1145

А вот ещё пример из той же книги
public class Parcel8 {
// Argument must be final to use inside
// anonymous inner class:
public Destination dest(final String dest) {
return new Destination {
private String label = dest;
public String readLabel { return label; }
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8;
Destination d = p.dest("Tanzania");
}
}
Дальше такой текст-пояснение:
If you’re defining an anonymous inner class and want to use an object that’s defined outside the anonymous inner class, the compiler requires that the argument reference be final, like the argument to dest( ). If you forget, you’ll get a compile-time error message.
Типа, объяснил.....

Dasar

ты мой вопрос внимательно прочитал?
ты на него ответил?

enochka1145

Это можешь решить только ты. Я лишь решил, что "другое место" - это не локальные переменные, а что-то другое (был пример).

Dasar

По буквам:
1. Есть внешняя и внутренняя функция
2. Есть локальная переменная во внешней функции
3. Есть проблема - внешняя функция может закончится, и уничтожить локальную переменную еще до того, как внутренняя функция закончит работу с этой переменной.
4. Есть решение: компилятор копирует значение этой локальной переменной в "другое место" (в область кучи)
Проблема решена?

enochka1145

Хочешь сказать, локальные переменные final размещаются в куче?

Dasar

> Хочешь сказать, локальные переменные final размещаются в куче?
Путаешь причину и следствие.
final означает, что переменная больше меняться не будет.
если переменная финал, то компилятор, когда встречает внутренную функцию, которая использует эту же переменную, может скопировать переменную в кучу: и обеспечить, чтобы
внешняя функция работала с копией в стеке, а внутренняя с копией в куче.
если финала - не будет, то получится, что копии смогут иметь разные значения.

bastii

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

bastii

т.е ae становится членом внутреннего класса, как и this внешнего класса.

enochka1145

> Они создают копию в куче.
Всё ясно. Всем спасибо!
"Вот когда мне так по-человечески объясняют..." (Криминальное чтиво)
P.S. (Но осадок в душе остался) Почему-то это нигде (Thinking in Java, The Java Language Specification) не объясняется.

enochka1145

Какого this? main вроде статическая.

enochka1145

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

bastii

А ну да, в этом примере нет this
Оставить комментарий
Имя или ник:
Комментарий: