WebClub - Всероссийский Клуб Веб-разработчиков
WebClub.RU » Архив » Понятие "final"

Понятие "final"


Дата публикации: 17-03-2013

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

final int max_value = 10;
Здесь, max_value инициализируется 10-ю и не может быть изменено позже.
Почему вам нужна final переменная? final переменная имеет следующие преимущества:

1. Ее значение не может быть изменено (она константа)
2. Она помогает в оптимизации компилятора

Любая попытка изменять значение final переменной, однажды инициализированной, приводит к ошибке во время компиляции (compile-time error). 2-й пункт выше немного интереснее. Когда переменная объявлена как final, компилятор знает, что ее значение не может быть изменено, так что она может непосредственно заменять значение переменной, где бы она не использовалась. Это уменьшает дополнительные затраты выборки значения переменной из памяти. И когда вы интенсивно используете такие переменные, это уменьшение может быть значительным.

Не обязательно инициализировать final переменную во время объявления. Инициализация может производиться позже, но должна быть выполнена перед первым использованием переменной. Такая final переменная называется "blank final". Если вы создаете переменную член blank final, вы должны инициализировать ее в каждом конструкторе. Это очевидно, потому что компилятор не может снаружи прослеживать все возможные последовательности потоков кодов, которые могут обращаться к этой переменной. Если бы он мог, то вам не нужен был бы отладчик! Точно так же, если локальная переменная создается как blank final, вы должны инициализировать ее перед первым использованием. Как только blank final инициализирована, ее значение не может быть изменено. Следующий код показывает использование переменных blank final:

/** Demonstrates the use of blank final. */
public class BlankFinalDemo {

/** A blank final member (should be initialized in every constructor). */
final int blankFinal;

/** Default constructor. */
BlankFinalDemo() {
this.blankFinal = 0;
}

/** Constructor to initialize the blank final member to the
specified value. */
BlankFinalDemo(int value) {
this.blankFinal = value;
}

/** Demonstrates the use of a local blank final. */
public void demo() {

// A local blank final (should be initialized before first use)
final int localBlankFinal;

//...

// Initialize the local blank final
localBlankFinal = 2;

System.out.println("demo(): Local blank final = " + localBlankFinal);

// Any further attempt to assign a value to the above
// "localBlankFinal" will result in a compile-time error

}

/** Main. */
public static void main(String[] args) {

// Initialize the member blank final
BlankFinalDemo obj = new BlankFinalDemo(1);
System.out.println("main(): Member blank final = " + obj.blankFinal);

// Demonstrate the use of a local blank final
obj.demo();

}

}
Здесь, мы имеем переменную член blankFinal, которая инициализируется в каждом конструкторе. А в методе demo(), мы имеем переменную localBlankFinal, которая инициализируется перед первым использованием (которое происходит в предложении println).
Метод может также быть создан final'ом следующим образом:

final void aFinalMethod() {
//...
}
Создавая его таким образом, вы указываете, что метод не может быть замещен подклассами класса. Вы можете сделать это в случае, если вы знаете, что метод в базовом классе - совершенный и его поведение не будет изменено подклассами. И опять, любая попытка отменить final метод в подклассе приведет к ошибке во время компиляции.
Вы можете создать класс final следующим образом:

final class aFinalClass {
// ...
}
Вы предположили это правильно. Final класс не может подклассифицироваться. Это требуется в ситуациях, когда вы знаете наверняка, что класс совершенен и никогда не будет нуждаться в производных. Java.lang.String и java.lang.StringBuffer - примеры final классов.
Интересно, что даже локальные переменные и параметры метода могут быть объявлены как final. Помимо того, что их целью является оптимизация, они играют еще одну особую роль. Внутренний класс может обращаться только к тем локальным переменным и параметрам, которые объявлены как final. Почему существует такое ограничение? Потому что объект внутреннего класса может входить в эффект после того как ваш метод закончил работу. В качестве примера рассмотрите следующий код:

import java.awt.*;
import java.awt.event.*;

/** Demonstrates the use of a local final variable. */
public class LocalFinalDemo {

/** Shows a frame. */
public void startDemo() {

// The window (the variable is final to make it accessible
// by the inner class)
final Frame wnd = new Frame("Local Final Demo");

// Display a message
Label lbl = new Label("Now close the frame", Label.CENTER);
wnd.add(BorderLayout.CENTER, lbl);

// Add a window listener to close the frame
class WH extends WindowAdapter {
Frame parent;
WH(Frame parent) {
this.parent = wnd;
}
public void windowClosing(WindowEvent we) {
if (parent == wnd) {
System.out.println("Same");
}
wnd.dispose();
wnd.setVisible(false);
System.exit(0);
}
}
wnd.addWindowListener(new WH(wnd));

// Show the window
wnd.pack();
wnd.setVisible(true);

}

/** Main. */
public static void main(String[] args) {

// Start the demo
LocalFinalDemo lfd = new LocalFinalDemo();
lfd.startDemo();

}

}
Здесь, main() создает образец LocalFinalDemo и затем запускает demo, которая состоит в отображении фрейма. Обратите внимание на использование final в определении объекта фрейма, wnd. Метод StartDemo() затем устанавливает UI и добавляет WindowListener, чтобы обработать закрытие фрейма. Наконец, он показывает фрейм и затем метод заканчивает работу.
Так как wnd - это final переменная, то становится возможным копирование значения переменной непосредственно во внутренний объект класса, таким образом увеличивая ее время жизни. Следовательно, даже если метод startDemo() возвратился, объект не будет уничтожен и будет доступен, когда вы закроете приложение.

Мы начали с простых вещей, но к концу, мы увидели больше граней использования ключевого слова final, которые являются действительно полезными.
Домен продается

Популярное

Не так давно в сети появился новый сервис, под названием Dead Man Zero. Этот сервис сделал...
Рынок социальных площадок уже давно стал стабильным. Несмотря на то, что время от времени...
Artisteer 4 – единственный в своем роде продукт, позволяющий автоматизировать работу над созданием...
Апрель 2024 (1)
Октябрь 2018 (14)
Февраль 2017 (3)
Январь 2017 (1)
Август 2016 (1)
Май 2016 (2)

Карта сайта: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41

Друзья сайта



Случайная цитата

Alan J. Perlis:

"FORTRAN — это не цветок, а сорняк: он вынослив, иногда расцветает и произрастает в каждом компьютере."

Опрос

Какой аудио плеер Вы используете?

Winamp
Light Alloy
foobar2000
Apollo
AIMP
1by1
iTunes
jetAudio
Другой...