1. Обзор
В этом уроке мы рассмотрим три ключевых слова Java: final, finally и finalize.
Хотя эти ключевые слова похожи друг на друга, каждое из них имеет совершенно другое значение в Java. Мы изучим назначение каждого из них и рассмотрим некоторые примеры с помощью небольшого кода.
2. последнее ключевое слово
Давайте сначала взглянем на ключевое слово final , где его использовать и почему. Мы можем применить ключевое слово final к объявлениям классов, методов, полей, переменных и параметров методов.
Однако это не оказывает одинакового эффекта на каждого из них :
- Создание класса final означает, что расширить этот класс будет невозможно
- Добавление final в метод означает, что переопределить этот метод будет невозможно
- Наконец, размещение final перед полем, переменной или параметром означает, что после присвоения ссылки она не может быть изменена (однако, если ссылка относится к изменяемому объекту, ее внутреннее состояние может измениться, несмотря на то, что оно окончательное).
Подробную статью о ключевом слове final можно найти здесь .
Давайте посмотрим, как работает ключевое слово final на некоторых примерах.
2.1. конечные поля, Параметры и Переменные
Давайте создадим Родительский класс с двумя int полями, окончательным одним и обычным не окончательным:
public class Parent { int field1 = 1; final int field2 = 2; Parent() { field1 = 2; // OK field2 = 3; // Compilation error } }
Как мы видим, компилятор запрещает нам присваивать новое значение полю 2 .
Давайте теперь добавим метод с обычным и последним аргументом:
void method1(int arg1, final int arg2) { arg1 = 2; // OK arg2 = 3; // Compilation error }
Аналогично полям, невозможно назначить что-либо arg2 , поскольку оно объявлено окончательным.
Теперь мы можем добавить второй метод, чтобы проиллюстрировать, как это работает с локальными переменными:
void method2() { final int localVar = 2; // OK localVar = 3; // Compilation error }
Ничего удивительного не происходит, компилятор не позволяет нам присваивать новое значение local Var после его первого присвоения.
2.2. окончательный метод
Теперь предположим , что мы делаем метод2 окончательным и создаем подкласс Родительского , скажем Дочернего , в котором мы пытаемся переопределить оба его метода суперкласса:
public class Child extends Parent { @Override void method1(int arg1, int arg2) { // OK } @Override final void method2() { // Compilation error } }
Как мы видим, нет никаких проблем с переопределением метода 1() , но мы получаем ошибку компиляции при попытке переопределить метод 2() .
2.3. заключительный урок
И, наконец, давайте сделаем Дочерний класс окончательным и попробуем создать его подкласс, Внук :
public final class Child extends Parent { // ... }
public class GrandChild extends Child { // Compilation error }
И снова компилятор жалуется. Класс Дочерний является окончательным, и поэтому его невозможно расширить.
3. наконец, Заблокируйте
Блок наконец является необязательным блоком для использования с оператором try/catch . В этом блоке мы включаем код для выполнения после структуры try/catch , независимо от того, возникает исключение или нет .
Его даже можно использовать с блоком try без какого-либо блока catch при условии, что мы включим наконец блок. Затем код будет выполнен после попытки или после возникновения исключения.
Здесь у нас есть подробная статья об обработке исключений в Java .
Теперь давайте продемонстрируем наконец блок в коротком примере. Мы создадим фиктивный метод main() со структурой try/catch/finally :
public static void main(String args[]) { try { System.out.println("Execute try block"); throw new Exception(); } catch (Exception e) { System.out.println("Execute catch block"); } finally { System.out.println("Execute finally block"); } }
Если мы запустим этот код, он выведет следующее:
Execute try block Execute catch block Execute finally block
Давайте теперь изменим метод, удалив блок catch (и добавив выбрасывает исключение в подпись).:
public static void main(String args[]) throws Exception { try { System.out.println("Execute try block"); throw new Exception(); } finally { System.out.println("Execute finally block"); } }
Результат сейчас:
Execute try block Execute finally block
Если мы теперь удалим инструкцию throw new Exception () , мы сможем заметить, что результат останется прежним. Наше наконец выполнение блока происходит каждый раз.
4. доработать Метод
И, наконец, метод finalize является защищенным методом, определенным в классе объектов . Он вызывается сборщиком мусора для объектов, на которые больше нет ссылок и которые были выбраны для сбора мусора .
Как и любой другой не окончательный метод, мы можем переопределить этот метод, чтобы определить поведение, которое должен иметь объект при сборе сборщиком мусора .
Опять же, подробную статью, описывающую метод finalize , можно найти здесь .
Давайте посмотрим на пример того, как это работает. Мы будем использовать System.gc() , чтобы предложить JVM для запуска сборки мусора :
@Override protected void finalize() throws Throwable { System.out.println("Execute finalize method"); super.finalize(); }
public static void main(String[] args) throws Exception { FinalizeObject object = new FinalizeObject(); object = null; System.gc(); Thread.sleep(1000); }
В этом примере мы переопределяем метод finalize() в нашем объекте и создаем метод main () , который создает экземпляр нашего объекта и немедленно удаляет ссылку, установив для созданной переменной значение null .
После этого мы вызываем System.gc() для запуска сборщика мусора (по крайней мере, мы ожидаем, что он запустится) и ждем секунду (просто чтобы убедиться, что JVM не завершит работу до того, как сборщик мусора получит возможность вызвать finalize() метод).
Результат выполнения этого кода должен быть:
Execute finalize method
Обратите внимание, что переопределение метода finalize() считается плохой практикой, поскольку его выполнение зависит от сборки мусора , которая находится в руках JVM . Кроме того, этот метод устарел начиная с Java 9.
5. Заключение
В этой статье мы кратко обсудили различия между тремя похожими ключевыми словами Java: final, finally и finalize .
Полный код статьи можно найти на GitHub.