В Java разрешается создавать
//: c06:BlankFinal .java // "Пустые" неизменные поля.
class Poppet {
private int i:
Poppet(int ii) { i = ii; }
}
public class BlankFinal {
private final int i = 0; // Инициализированная константа private final int j; // Пустая константа private final Poppet p; // Пустая константа-ссылка II Пустые константы НЕОБХОДИМО инициализировать // в конструкторе: public BlankFinalО {
j = 1; // Инициализация пустой константы р = new Poppet(l); // Инициализация пустой неизменной ссылки
}
public BlankFinal(int х) {
j = х; // Инициализация пустой константы р = new Poppet(x), // Инициализация пустой неизменной ссылки
}
public static void main(String[] args) { new BlankFinal О; new BlankFinal(47),
}
} ///:-
Значения неизменных (final) переменных обязательно должны присваиваться или в выражении, записываемом в точке определения переменной, или в каждом из конструкторов класса. Тем самым гарантируется инициализация полей, объявленных как final, перед их использованием.
Неизменные аргументы
Java позволяет вам объявлять неизменными аргументы метода, объявляя их с ключевым словом final в списке аргументов. Это значит, что метод не может изменить значение, на которое указывает передаваемая ссылка:
II: reusing/FinalArguments.java II Использование final с аргументами метода
class Gizmo {
public void spinO {}
}
public class Final Arguments { void with(final Gizmo g) {
}
void without(Gizmo g) {
g = new GizmoO: II Разрешено -- g не является final g.spinO;
}
II void f(final int i) { i++, } II Нельзя изменять. II неизменные примитивы доступны только для чтения: int g(final int i) { return i + 1; } public static void main(String[] args) {
Final Arguments bf = new FinalArgumentsO;
bf .without(null):
}
} ///.-
Методы f() и g() показывают, что происходит при передаче методу примитивов с пометкой final: их значение можно прочитать, но изменить его не удастся.
Неизменные методы
Неизменные методы используются по двум причинам. Первая причина — «блокировка» метода, чтобы производные классы не могли изменить его содержание. Это делается по соображениям проектирования, когда вам точно надо знать, что поведение метода не изменится при наследовании.
Второй причиной в прошлом считалась эффективность. В более ранних реализациях Java объявление метода с ключевым словом final позволяло компилятору превращать все вызовы такого метода во
В последних версиях Java виртуальная машина выявляет подобные ситуации и устраняет лишние передачи управления при оптимизации, поэтому использовать final для методов уже не обязательно — и более того, нежелательно.
Спецификаторы final и private
Любой закрытый (private) метод в классе косвенно является неизменным (final) методом. Так как вы не в силах получить доступ к закрытому методу, то не сможете и переопределить его. Ключевое слово final можно добавить к закрытому методу, но его присутствие ни на что не повлияет.
Это может вызвать недоразумения, так как при попытке переопределения закрытого (private) метода, также неявно являющегося final, все вроде бы работает и компилятор не выдает сообщений об ошибках:
//• reusi ng/Fi nalOverri di ngll1usi on.java
// Все выглядет так, будто закрытый (и неизменный) метод
// можно переопределить, но это заблуждение.
import static net mindview.util Print.*,
class WithFinals {
// To же, что и просто private:
private final void f() { printC'WithFinals f()M), }
// Также автоматически является final
private void g() { printC'WithFinals.g()"), }
class OverridingPrivate extends WithFinals {
private final void f() {
printC'OverridingPrivate fO").
}
private void g() {
printC'OverridingPrivate g()").
}
}
class 0verridingPrivate2 extends OverridingPrivate {
public final void f() {
print("0verridingPrivate2 f()").
}
public void g() {
print("0verridingPrivate2 g()").
}
public class FinalOverridingll1usion {