finalキーワードといくつかの提案を深く理解する

3953 ワード

引用子:finalキーワードといえば、みんながすぐに基本的な役割を思い出すと信じています.では、まずわずかな行で振り返ってみましょう.
一、finalキーワードの意味
finalはJavaの保持キーであり、メンバー変数、メソッド、クラス、およびローカル変数にマークできます.オブジェクトをfinalとして宣言すると、このオブジェクトの参照を変更することはできません.finalに修飾されたオブジェクトを再割り当てしようとすると、コンパイラはエラーを報告します.
二、使い方
1.修飾変数
finalはメンバー変数またはローカル変数に修飾されているので、この変数はfinal変数と呼ぶことができます.これにより、栗:定数を挙げることができます(定数の代わりに列挙クラスを使用することをお勧めしますが).
finalで修飾された変数を再割り当てすると、コンパイラは図:cannot assign a value to final variable.(final変数に値を割り当てることはできません)
2.修飾方法
finalに修飾された方法は布団類に書き換えることができません.
「finalメソッドを使用する理由は2つあります.1つ目は、継承クラスがその意味を変更しないようにメソッドをロックすることです.2つ目は効率性です.初期のJavaインプリメンテーションバージョンでは、finalメソッドがインラインコールに変換されます.しかし、メソッドが膨大すぎると、インラインコールによるパフォーマンスの向上は見られません.最近のJavaバージョンでは、これらの最適化はfinalメソッドで行われました.-『Javaプログラミング思想』より抜粋します.
したがって、メソッドの機能が十分に完全で、サブクラスで変更する必要がないと判断した場合は、このメソッドをfinalと宣言できます.finalメソッドは非finalメソッドよりも速く、コンパイル時に静的にバインドされているため、実行時に動的にバインドする必要はありません(プログラミング思想で述べたように、現在のいくつかの新しいJDKでは、パフォーマンスの差はほとんどありません).
(書き換えを試みるとコンパイラがエラーを報告します).
注意:クラスのprivateメソッドはfinalメソッドとして暗黙的に指定されます.
3.修飾類
クラスがfinalによって修飾されている場合、この機能は通常完全であることを示します.このクラスは継承できません.そしてfinalクラスのすべての方法は暗黙的にfinalに修飾されます.
4.ps:匿名クラスのすべての変数はfinalでなければなりません.
三、キーワードfinalのメリットのまとめ
finalキーワードはパフォーマンスを向上させた.JVMとJavaアプリケーションはfinal変数をキャッシュします.final変数は、追加の同期オーバーヘッドを必要とせずに、マルチスレッド環境で安全に共有できます.finalキーワードを使用すると、JVMはメソッド、変数、クラスを最適化します.可変クラスの場合、オブジェクトは読み取り専用であり、追加の同期オーバーヘッドを必要とせずにマルチスレッド環境で安全に共有できます.
四、『Effective Java』からのアドバイス
この本の第17条:継承のために設計され、ドキュメントの説明を提供するか、継承を禁止するか.
このエントリは、クラスが継承のために設計されていない場合、このクラスは継承を禁止されるべきであることを示しています(少し回りくどいように聞こえますが、よく考えた設計思想は良いです)、そうでなければ、十分なドキュメントと注釈を提供するべきです(java.util.AbstractCollectionというスケルトン実装の注釈ドキュメント仕様を参照).
布団類の類化を禁止する方法は通常2つあります.
1.すべてのコンストラクタをプライベート(private)またはパケットレベルプライベート(default)に設定し、コンストラクタの代わりに静的ファクトリメソッドを使用する.
2.クラスをfinalとしてマークします.
五、考える
1.いくつかの思考は振り返って私达の日常の中のプログラムを见て、私达はすでにそんなにわざとfinalを使うことに惯れていないかもしれなくて、せいぜい定数を书く时に使って、しかし実际に私达の多くの种类、方法あるいは変数は変える必要はなくて、あるいは継承されません.例えば私は『Effective Java』のこの項目を読んだばかりで、自分がやっているプロジェクトを振り返ってみました.まず自分のdomain層のいくつかのクラスをfinalと表記しました.これらのクラスは継承できないと思います.継承したのは設計に合わないし、プログラムの実行に異常がないと思います.同時に修正されたのは私の依存注入方式です(私の前のブログを参照:Spring注釈依存注入の3つの方式の長所と短所と優先選択)
私は自分がクラスを設計する時の考え方を改めて直しました:前に自分がクラスを書く準備をしていたとき(通常はクラスにfinalを付けない===)、このクラス(変数や方法)は変えられないと思っていたかもしれませんが、強いという考えがあったときにfinalを加えることができましたが、今は:このクラスは彼を布団でクラス化する必要はありませんか?もし後でプロジェクトが更新され、反復中に必要でなければ、私はためらうことなく彼にfinalを加えます.
2.「finalキーワードはパフォーマンスを向上させる」?
それを発見した後、私は中毒かもしれないし、finalを加えることができるところに加えて、性能を改善したと思っていたので、心の中では楽しかったです.実はこの“性能を高めます”に対して少しずっと少しの疑問があって、そこで私は振り返ってStack Overflowの上で1周して、私の欲しい答えを見つけました:Does use of final keyword in Java improve the performance?
大物は、通常はできないと指摘しています.方法については、HotPotは本当に書き換えられたかどうかを追跡し、書き換えられていない収束方法を最適化することができます.これは、クラスがこの方法を書き換えたまでロードされ、これらの優位性を取り消すことができます(または部分的に取り消すことができます).(もちろん、これはHotPotを使用していると仮定していますが、これまでで最も一般的なJVMだったので...)
その後、大物は私たちがこのようなわずかな性能のために頭を悩ますべきではないと指摘し、良い構造のコードと可読性の優れたコードを明確に設計し、書くことを提案した.(ここでは『Effective Java』の第55条:慎重に最適化を行う上で指摘されている核心:最適化の格言は:最適化を行わないことである)(上の『Javaプログラミング思想』の最後の言葉も検証した)
3.ローカル変数およびパラメータのfinalについて
次に私の局所変数と方法のパラメータをfinalと表記しようとしたが,2と同様に中毒が深くなった.しかし、私はこれに対して同じ疑問を持っています.そして、Stack Overflowで経験証のもう一つの結論を得ました.局所変数とパラメータのfinalは、私たちの性能を向上させることはできません.バイトコードにも書かれません.そこで私はキーボードを操作してパチパチと何行かのコードを叩いてコンパイルし、JD-GUIのような逆コンパイルツールで開きました.
まず、ソースコードを見てみましょう.
public class FinalTest { private static void say(final int number) { System.out.println(“number: ” + number); }
public static void main(String[] args) {
    final int num = 0;
    say(num);
}

}
コンパイルされた.classファイルを見てみましょう.
public class FinalTest { public FinalTest() { }
private static void say(int number) {
    System.out.println("number: " + number);
}

public static void main(String[] args) {
    int num = false;
    say(0);
}

}
バイトコードを書き込むときに最適化されていることがわかりますが、finalはコンパイル時に静的に制限されているだけで、値を割り当てることはできません(参照を変更します).