Установка окончательного атрибута класса - PullRequest
4 голосов
/ 07 апреля 2011

Можно ли установить значение для окончательного атрибута из метода Private, вызываемого из конструктора этого объекта?

public class FinalTest {
  private final Object a;
  //Constructor
  public FinalTest() {
    setA();
  }

  private void setA() {
    a = new Object;
  }
}

Для приведенного выше класса компилятор выдает ошибку, в которой говорится, что я не могуустановите значение для «а» из метода.

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

Ответы [ 4 ]

10 голосов
/ 07 апреля 2011

Это не разрешено, потому что вы могли бы вызвать setA() через какой-то другой неконструктивный метод, который впоследствии нарушил бы окончательную защиту. Поскольку final - это принудительная операция времени компиляции, компилятор принудительно выполняет final, заставляя инициализацию происходить в конструкторах или в строке.

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

public class FinalTest {
  private final Object a;
  //Constructor
  public FinalTest() {
    setA();
  }

  private void setA() {
    a = new Object;
  }

  public void doSomething() {
   this.setA(); // not good because a is final
  }
}
2 голосов
/ 03 ноября 2011

Только примечание: компилятор имеет , чтобы предположить худший вариант развития событий. Объявляя атрибут "final", компилятор должен гарантировать , что атрибут не может быть изменен вне конструктора.

В случае, когда метод вызывается с использованием отражения (например), компилятор никогда его не увидит. Гораздо проще доказать, что что-то возможно, чем невозможно, поэтому компилятор работает так, как работает.

1 голос
/ 07 апреля 2011

Зачем вам нужно устанавливать значение конечной переменной из частного метода? Вы можете сделать это следующим образом:

public class FinalTest {
   private final Object a;
   {
      a=new Object();
   }

   //Constructor
   public FinalTest() {
   }
}

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

1 голос
/ 07 апреля 2011

Окончательная проверка выполняется во время компиляции, а не во время выполнения. В вашем случае компилятор не может быть уверен, что setA не будет вызван из какого-либо другого метода.

...