理解final,finally,finalizeの3つの違い


finalキーワード
私たちはまずfinalについて話します.次の4つの場所で使用できます.
1.静的および非静的を含む変数を定義します.
2.メソッドのパラメータを定義します.
3.メソッドを定義します.
4.クラスを定義します.
それぞれの場合のfinalの役割を順番に振り返ってみましょう.
まず第1のケースを見ると、final修飾が基本タイプであれば、この変数が与えられた値が可変ではないこと、すなわち定数であることを示す.final修飾がオブジェクトである場合、この変数に付与された参照は可変であることを示します.ここで注意しなければならないのは、変更できないのはこの変数が保存した参照だけで、この参照が指すオブジェクトではありません.
第2の場合、finalの意味は第1の場合と同じである.実際には、前の2つのケースについて、finalの意味をより適切に表す記述があります.これは、1つの変数またはメソッドパラメータがfinalによって修飾されると、1回しか付与されないことを示しますが、JAVA仮想マシンが変数に設定したデフォルト値は1回の付与として記録されません.
finalによって修飾された変数は初期化されなければならない.初期化の方法は次のとおりです.
1.定義時に初期化します.
2.final変数は初期化ブロックで初期化でき、静的初期化ブロックで初期化できない.
3.静的final変数は静的初期化ブロックで初期化でき、初期化ブロックで初期化できない.
4.final変数はクラスのコンストラクタで初期化することもできますが、静的final変数はできません.
次のコードを使用して、上記の観点を検証します.
Javaコード
public class FinalTest {
//        
public final int A = 10;
public final int B;
//          
{
B = 20;
}
//    final               
// public final int C;
// static {
// C = 30;
// }
//     ,       
public static final int STATIC_D = 40;
public static final int STATIC_E;
//     ,           
static {
STATIC_E = 50;
}
//                
// public static final int STATIC_F;
// {
// STATIC_F = 60;
// }
public final int G;
//   final             
// public static final int STATIC_H;
//         
public FinalTest() {
G = 70;
//   final             
// STATIC_H = 80;
//  final         ,     
// A = 99;
// STATIC_D = 99;
}
// final       ,       
// public final int I;
//   final       ,       
// public static final int STATIC_J;
}

上記のコードを実行した後、final変数(定数)と静的final変数(静的定数)が
初期化されると、コンパイルがエラーを報告します.
finalで修飾した変数(定数)は非finalの変数(一般変数)よりも効率的であるため,我々は実
インタープログラミングでは、通常の変数の代わりに定数をできるだけ多く使うべきであり、これも良いプログラミング習慣である.
finalがメソッドを定義するとき、どのような効果がありますか?ご存じのように、この方法は
サブクラスは書き換えられますが、これは布団クラスの継承に影響しません.コードを書いて検証します.
Javaコード
class ParentClass {
public final void TestFinal() {
System.out.println("  --    final  ");
}
}
public class SubClass extends ParentClass {
/**
*       (override)   final  ,        
*/
// public void TestFinal() {
// System.out.println("  --  final  ");
// }
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.TestFinal();
}
}

ここで特に説明する必要があるのは、privateアクセス権を持つ方法でもfinal修飾を増やすことができるが、サブクラス
privateメソッドを継承できないため、書き換えることもできません.コンパイラはprivateメソッドを処理する際にfinalメソッドに従います
これにより、メソッドが呼び出されたときの効率を向上させることができる.ただし、子クラスは親クラスの
privateメソッドは同じ構造のメソッドを有し、
しかし、これは書き換えの効果を生むものではなく、必然的なつながりもありません.
最後にfinalがクラスに使用されている状況を振り返ってみましょう.これは皆さんもよく知っているはずです.私たちが一番よく使うからです.
Stringクラスはfinalです.finalクラスは継承を許さないため、コンパイラは処理時にそのすべての方法を
finalのため、finalクラスは通常のクラスよりも効率的です.
キーワードabstractによって定義される抽象クラスには、継承されたサブクラスによって再ロードされなければならない抽象メソッドが含まれているため、finalとabstractを同時に使用して同じクラスを修飾することはできません.
同じ理屈で、
finalもインタフェースを修飾するために使用できません.finalのクラスのすべてのメソッドは書き換えられませんが、これはfinalのクラスの属性(変数)値も変更できないことを意味しません.finalクラスの属性値を変更できないようにするには、final修飾を追加する必要があります.次の例を参照してください.
Javaコード
public final class FinalTest {
int i = 10;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;
System.out.println(ft.i);
}
}

上記のコードを実行してみると、初期化時の10ではなく99になります.
finally文
次にfinallyの使い方を振り返ってみましょう.これは簡単ですtry/catch文でしか使えません
また、この文が最終的に常に実行され、異常な統一出口を示す文ブロックが付属しています.次のコードを見てください.
Javaコード
public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("       ");
} finally {
System.out.println("   finally   ");
}
}
}

実行結果はfinallyの役割を示します.
1.プログラムが異常を投げ出した
2.finally文ブロックの実行
キャプチャプログラムから放出された異常の後、処理もせず、上への異常の放出も継続せず、良好ではないことに注意してください.
プログラムの実行中に発生したエラー(異常な損失をもたらす)を隠すプログラミング習慣がありますが、ここでは簡単なプレゼンテーションですので、勉強しないでください.では、finally文ブロックが実行されない場合はありませんか?皆さんは考えているかもしれません
return,continue,breakの3つは,コード順序実行文の法則を乱すことができる.では試してみましょう
3つの文がfinally文ブロックの実行に影響するかどうか:
Javaコード
public final class FinallyTest {
//   return  
public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("   finally  ");
}
return null;
}
//   continue  
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("   finally  ");
}
}
}
//   break  
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("   finally  ");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
//   return  
ft.testReturn();
System.out.println();
//   continue  
ft.testContinue();
System.out.println();
//   break  
ft.testBreak();
}
}
class ReturnClass {
public ReturnClass() {
System.out.println("   return  ");
}
}

上記のコードの実行結果は次のとおりです.
1.return文の実行
2.finally文が実行されました
3.
4. 0
5.finally文の実行
6. 1
7.finally文の実行
8. 2
9.finally文が実行されました
10.
11. 0
12.finally文の実行
13. 1
14.finally文の実行
明らかに、return、continue、breakはfinally文ブロックの実行を阻止できなかった.出力の結果から見ると、
return文はfinally文ブロックの前に実行されたようですが、実際にはそうですか?考えてみましょうreturn文
の役割は何ですか?は、現在のメソッドを終了し、値またはオブジェクトを返します.finally文ブロックがreturn語である場合
文の後に実行されると、return文が実行された後、現在のメソッドが終了し、finally文ブロックがどのように
実行は?したがって、正しい実行順序は、コンパイラがreturn new ReturnClass()をコンパイルしていること、の場合、
これを2つのステップに分けて、new ReturnClass()とreturn、前のオブジェクトを作成した文はfinally文ブロックの前に実行され、後のreturn文はfinally文ブロックの後に実行され、つまりfinally文ブロックはプログラムがメソッドを終了する前に実行されます.同様に、finally文ブロックは、ループがスキップされ、ブレークされる前に実行される.
finalizeメソッド
最後にfinalizeを見てみましょう.java.lang.Objectクラスに属するメソッドです.定義は次のとおりです.
Javaコード
protected void finalize() throws Throwable { }

周知のように、finalize()メソッドはGC(garbage collector)の動作メカニズムの一部であり、GCに関する知識は
後続の章で振り返ります.
ここでfinalize()メソッドの役割についてだけお話しします.
finalize()メソッドは、GCが依存するオブジェクトをクリーンアップするときに呼び出され、実行中にキャプチャできないものが投げ出された場合に呼び出されます.
取得された例外(uncaught exception)は、GCが変更オブジェクトのクリーンアップを終了し、この例外は無視されます.まで
次のGCがこのオブジェクトのクリーンアップを開始すると、そのfinalize()が再び呼び出されます.
次の例を参照してください.
Javaコード
public final class FinallyTest {
//   finalize()  
protected void finalize() throws Throwable {
System.out.println("   finalize()  ");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}

実行結果は次のとおりです.
•finalize()メソッドの実行
プログラムはjava.lang.Systemクラスのgc()メソッドを呼び出し、GCの実行を引き起こし、GCはftオブジェクトをクリーンアップするときに呼び出した.
のfinalize()メソッドなので、上記の出力結果が得られます.System.gc()を呼び出すのは、次の行のコードを呼び出すのと同じです.
Javaコード
Runtime.getRuntime().gc();

呼び出す役割は、ゴミ収集器(GC)の起動を推奨し、不要なオブジェクトをクリーンアップしてメモリ領域を解放することですが、GC
の起動は一定ではありません.これはJAVA仮想マシンによって決まります.JAVA仮想マシンが停止するまで、一部のオブジェクトの
finalize()は実行されていない可能性がありますが、すべてのオブジェクトを保証するこの方法はJAVA仮想マシンで停止します.
前に必ず呼び出されますか?答えはSystemクラスを呼び出す別の方法です.
Javaコード
public static void runFinalizersOnExit(boolean value) {
//other code
}

このメソッドにtrueを入力することで、オブジェクトのfinalize()メソッドがJAVA仮想マシンが停止する前に必ず実行されることを保証します.
残念ながら、この方法は安全ではありません.有用なオブジェクトfinalize()が誤呼び出されるため、すでに
使用に賛成されなくなった.
finalize()はObjectクラスに属するため、すべてのクラスにこのメソッドがあり、Objectの任意のサブクラスは書き換えることができます.
(override)この方法は、システムリソースを解放するか、入出力ストリームを閉じるなどの他のクリーンアップ作業を行う.
以上の知識を振り返ることで、final、finally、finalizeの使い方の違いはよくわかっていると思います.