徹底的なインタビュー3:ファイナル、ファイナル、ファイナライズの深い理解

1つ、最後

ファイナルブロンズ

Finalは、クラス、メソッド、および変数を変更できます。

  • クラスを変更すると、このクラスを継承できないことを意味します。
  • メソッドを変更する場合、このメソッドをオーバーライドできないことを意味します。
  • 変数を変更するときに初期化する必要があります。コードが定義されているときにコードが高速な場合は、コンストラクターで初期化できます。一度初期化すると、変更できません。

最終王

1.ローカル変数にアクセスするために匿名内部クラスにfinalを追加する必要があるのはなぜですか?

次のコードを確認します。

public class Test {
    
    
    public static void main(String[] args) {
    
    
        int a = 8;
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println(a);
            }
        }).start();
    }
}

jdk1.8より前は、変数がfinalを追加しなかったため、このコードはコンパイルに失敗しました。ただし、jdkが1.8になると、finalを追加する必要はなくなりますが、コンパイラーは自動的にfinalを追加します。

Java構文で最終変更を使用する必要があるのはなぜですか?

内部クラスTest $ 1.classの逆コンパイルされたコードを逆コンパイルしましょう

final class Test$1 implements Runnable {
    
    
    Test$1(int var1) {
    
    
        this.val$a = var1;
    }

    public void run() {
    
    
        System.out.println(this.val$a);
    }
}

逆コンパイルされたコードは多少省略されており、val $ a変数の定義が欠落しています。これは重要ではなく、問題ではありません。

上記の逆コンパイルされたコードからわかるように、匿名内部クラスがローカル変数にアクセスできる理由は、このローカル変数の値が最下層の匿名内部クラスに渡され、のメンバー変数として存在するためです。匿名内部クラス。この値転送プロセスは、匿名内部クラスのコンストラクターによって完了されます。

データがコピーされた後、最終的な変更を使用しない場合は、元のローカル変数を変更できるためです。ローカル変数が変更された場合、匿名内部クラスは認識しません(直接使用されるローカル変数ではなく、ローカル不変条件の値をコピーするだけだからです)。栗は次のとおりです。元のローカル変数はオブジェクトAを指します。匿名内部クラスが作成された後、匿名内部クラスのメンバー変数もAオブジェクトを指します。しかし、しばらくすると、ローカル変数の値は別のBオブジェクトを指しますが、この時点では、匿名の内部クラスは元のAオブジェクトを指します。その後、プログラムは実行を継続します。これにより、プログラムの実行が予想とは異なる場合があります。

2.最終として宣言されたローカル変数に対してJVMが行ったパフォーマンスの最適化は何ですか?

この質問はもっと複雑です。R大学はすでにこれについてより詳細な分析を行っています。興味があれば見てください。

[https://www.zhihu.com/question/21762917]:

結論は次のとおりです。コンパイルできるという前提で、ローカル変数が最終的なキーワード変更の有無に関係なく宣言されているかどうかに関係なく、そのアクセスの効率は同じです。

二,finally

finally これは、プログラムを確実に実行するためのメカニズムです。Javaのキーワードでもあります。一般的に、finallyは通常、単独では使用されません。通常、try ... finallyblockまたはtry ... catchとともに使用されます。 。最終的に。

  • finalブロックは、tryブロックが実行されたときにのみ実行され、finallyは単独では存在しません。
  • finalブロックは、tryブロックの実行が完了した後、またはtryブロックが完了しなかった後、制御転送ステートメントの前に実行されますが、次は制御転送ステートメント(return / continue / break)です。
public class Test {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(getNum());
    }
    public static int getNum() {
    
    
        int a = 0;
        try {
    
    
            a = 1;
            return a;
        } finally {
    
    
            ++a;
            System.out.println("finally执行");
        }
    }
}

実行出力:

finally执行
1
  • tryステートメントブロックにexceptionとそのサブクラスに属する例外がある場合は、ジャンプして処理をキャッチします。
  • 例外に属さない例外とそのサブクラスがtryステートメントブロックで発生した場合は、最終処理にジャンプします
  • catchステートメントブロックで新しい例外が発生した場合は、最終処理にジャンプします
  • try ... catchにreturnステートメントがある場合、戻り値は一時的に格納され、finallyが実行された後、戻り値または返された一時値が実行されます。

3、ファイナライズ

Javaテクノロジでは、finalize()メソッドを使用して、ガベージコレクタがオブジェクトをメモリからクリアする前に必要なクリーンアップ作業を実行できます。このメソッドは、オブジェクトが参照されていないと判断したときにガベージコレクターによって呼び出されます。Objectクラスで定義されているため、すべてのクラスが継承します。サブクラスはfinalize()メソッドをオーバーライドして、システムリソースを整理したり、その他のクリーンアップタスクを実行したりします。

ファイナライズは次のように機能します。ガベージコレクターがオブジェクトによって占有されているメモリを解放する準備ができると、最初にfinalizeメソッドを呼び出し、次にガベージコレクションアクションが発生すると、オブジェクトによって占有されているメモリが実際に回復されます。ガベージコレクションはメモリにのみ関連しています。

JavaとC ++の大きな違いは、JavaがJavaでできること自动管理内存です。これは、自動回復メカニズムGCであるためfinalize、メソッドが(のオブジェクトをジャンクする回復時間の)タイムリーな実装になることを保証するものでありません。不確かです)、実行される保証はありません。

つまり、finalizeの実行期間が不確実であり、finalizeメソッドを使用してガベージコレクションを実行することはできません。リソースが不足する前にgcがトリガーされない場合があるため、表示することをお勧めします。リソースが使い果たされたときcloseメソッドなどのreleaseメソッド。さらに、finalizeメソッドも例外を引き起こします。

したがって、日常の開発でfinalizeメソッドを使用することは推奨していません。

おすすめ

転載: blog.csdn.net/u013277209/article/details/109450934