Javaでのfinal、finally、finalizeの違い

JavaでのFinal、Finally、およびFinalizeの違い

1. 概要

このチュートリアルでは、final, finally finalize.の3つのJavaキーワードの概要を説明します。

これらのキーワードは互いに似ていますが、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フィールド、パラメーター、および変数

2つのint フィールド、finalフィールド、および通常の非最終フィールドを持つParentクラスを作成しましょう。

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
    }

フィールドと同様に、finalとして宣言されているため、arg2に何かを割り当てることはできません。

ローカル変数でこれがどのように機能するかを説明するために、2番目のメソッドを追加できます。

    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クラスをfinalにして、そのサブクラス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

finallyブロックが含まれていれば、catchブロックなしでtryブロックと一緒に使用することも可能です。 コードは、tryの後、または例外がスローされた後に実行されます。

Javahereでの例外処理に関する詳細な記事があります。

次に、短い例でfinallyブロックを示します。 try/catch/finally構造を持つダミーのmain()メソッドを作成します。

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を実行し(少なくとも実行されると予想されます)、1秒待ちます(JVMが%の前にシャットダウンしないようにするためです)。 (t3)sはfinalize()メソッドを呼び出す機会があります)。

このコード実行の出力は次のようになります。

Execute finalize method

JVMの手元にあるgarbage collectionに実行が依存するため、finalize()メソッドをオーバーライドすることは悪い習慣と見なされることに注意してください。 Plus, this method has been deprecated since Java 9.

5. 結論

この記事では、3つのJava類似キーワード(final, finallyfinalize)の違いについて簡単に説明しました。

記事の完全なコードはover on GitHub.で見つけることができます