Различия между финальным, окончательным и финализированным в Java

Различия между финалом, финалом и финализацией в Java

1. обзор

В этом руководстве мы рассмотрим три ключевых слова Java:final, finally andfinalize.

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

2. final ключевое слово

Давайте сначала посмотрим на ключевое словоfinal, где его использовать и почему. We can apply the final keyword to class, method, field, variable and method parameter declarations.

It doesn’t have the same effect on each of them though:

  • Создание классаfinal означает, что расширение этого класса невозможно.

  • Добавлениеfinal к методу означает, что переопределить этот метод будет невозможно.

  • Наконец, размещениеfinal перед полем, переменной или параметром означает, что после назначения ссылки ее нельзя изменить (однако, если ссылка относится к изменяемому объекту, его внутреннее состояние может измениться, несмотря на окончательный)

Подробную статью о ключевом словеfinal можно найтиhere.

Давайте посмотрим, как ключевое словоfinal работает на нескольких примерах.

2.1. final Поля, параметры и переменные

Давайте создадим классParent с двумя полямиint , однимfinal и обычным незавершенным:

public class Parent {

    int field1 = 1;
    final int field2 = 2;

    Parent() {
        field1 = 2; // OK
        field2 = 3; // Compilation error
    }

}

Как мы видим, компилятор запрещает нам присваивать новое значениеfield2.

Давайте теперь добавим метод с обычным и последним аргументом:

    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
    }

Ничего удивительного не происходит, компилятор не позволяет нам присвоить новое значениеlocalVar после его первого присвоения.

2.2. final Метод

Теперь предположим, что мы сделалиmethod2 final и создали подклассParent, скажем,Child, в котором мы пытаемся переопределить оба его метода суперкласса:

public class Child extends Parent {

    @Override
    void method1(int arg1, int arg2) {
        // OK
    }

    @Override
    final void method2() {
        // Compilation error
    }

}

Как мы видим, проблем с переопределениемmethod1() нет, но мы получаем ошибку компиляции при попытке переопределитьmethod2().

2.3. final Класс

И наконец, давайте сделаем классChild финальным и попробуем создать его подклассGrandChild:

public final class Child extends Parent {
    // ...
}
public class GrandChild extends Child {
    // Compilation error
}

Еще раз, компилятор жалуется. КлассChild является окончательным и поэтому его невозможно расширить.

3. finally Блок

Блокfinally - это необязательный блок для использования с операторомtry/catch. In this block, we include code to execute after the try/catch structure, whether an exception is thrown or not.

Его даже можно использовать с блокомtry без какого-либо блокаcatch, при условии, что мы включаем блокfinally. Затем код будет выполнен послеtry или после создания исключения.

У нас есть подробная статья об обработке исключений в Javahere.

Теперь давайте продемонстрируем блокfinally на коротком примере. Мы создадим фиктивный метод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 (и добавивthrows Exception в подпись):

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(), то увидим, что результат остается прежним. Наш блокfinally исполняется каждый раз.

4. finalize Метод

И, наконец, методfinalize - это защищенный метод, определенный вObject class. It’s called by the garbage collector on objects that aren’t referenced anymore and have been selected for garbage collection.

Как и любой другой незавершенный метод, мы можем переопределить этот метод, чтобы определить поведение, которое должен иметь объект при сбореgarbage collector.

Опять же, подробную статью, посвященную методуfinalize, можно найти вhere.

Давайте посмотрим на примере, как это работает. Мы будем использоватьSystem.gc(), чтобы предложитьJVM запускатьgarbage collection:

    @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() для запускаgarbage collector (по крайней мере, мы ожидаем его запуска) и ждем секунду (просто для того, чтобы убедиться, чтоJVM не отключится доJVM (t3) s имеет возможность вызвать методfinalize()).

Результат выполнения этого кода должен быть:

Execute finalize method

Обратите внимание, что переопределение методаfinalize() считается плохой практикой, поскольку его выполнение зависит отgarbage collection, который находится в рукахJVM. Plus, this method has been deprecated since Java 9.

5. Заключение

В этой статье мы кратко обсудили различия между тремя похожими ключевыми словами Java:final, finally иfinalize.

Полный код статьи можно найтиover on GitHub.