Каков эффект объявления последней переменной в методах?

Классический пример простого сервера:

class ThreadPerTaskSocketServer {
   public static void main(String[] args) throws IOException {
      ServerSocket socket = new ServerSocket(80);
      while (true) {
          final Socket connection = socket.accept();
          Runnable task = new Runnable() {
              public void run() {
                 handleRequest(connection);
              }
          };
          new Thread(task).start();
      }
   }
}

Почему должен Socket будьте объявлены как final? Это потому что новое Thread это обрабатывает запрос, мог вернуться к socket переменная в методе и причине своего рода ConcurrentModificationException?

7
задан Finbarr 9 May 2010 в 19:39
поделиться

6 ответов

В этом случае переменная должна быть окончательной для использования в анонимной имплементации Runnable .

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

13
ответ дан 6 December 2019 в 09:18
поделиться

Вы должны объявить его final, а не только should. Без этого компилятор не сможет использовать его в анонимной реализации класса Runnable.

2
ответ дан 6 December 2019 в 09:18
поделиться

Он не предназначен для устранения исключения ConcurrentModificationException. Любая локальная переменная, используемая внутри вложенного класса метода (например, анонимного внутреннего класса), должна быть объявлена ​​как final. См. Аналогичное обсуждение на прошлой неделе здесь:

локальные внутренние классы метода, обращающиеся к локальным переменным метода

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

0
ответ дан 6 December 2019 в 09:18
поделиться

Рассмотрим этот пример:

class A {
  B foo() {
    final C c;
    return new B() {
      void goo() {
        // do something with c
      }
    }
  }
}
// somewhere else in the code
A a = new A();
B b = a.foo();
b.goo();

Если c был not final, то когда вы дойдете до b.goo(), он будет указывать на мусор, поскольку этот c будет собран - Локальная переменная после окончания вызова метода.

3
ответ дан 6 December 2019 в 09:18
поделиться

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

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

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

примечание: http://renaud.waldura.com/doc/java/final-keyword.shtml#vars

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

2
ответ дан 6 December 2019 в 09:18
поделиться

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

Поскольку соединение является локальной переменной, ее невозможно разделить между потоками. Поскольку он не используется совместно между потоками, вам нужно сделать его final , поэтому не имеет значения, что это локальная переменная (ее можно рассматривать скорее как постоянное значение).

0
ответ дан 6 December 2019 в 09:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: