明らかに、私は前に最終的なキーワードのために研究ノートを作らなければなりませんでした。。。OK。。。地元のドキュメントライブラリを長い間検索しましたが、見つかりませんでした。作成して確認してください〜
この作品は主に参考用です:「あなたは__を聞いてい ます」あなたは本当にファイナルを理解していると思いますか?
学び、よく整理され、推奨されます〜
重要な部分のみを整理します。詳細については、元のブログ投稿を参照してください(特にパート4とパート6)。
1つ、最後の紹介
- Finalは、変数、メソッド、およびクラスを変更して、変更されたコンテンツが割り当てられた後は変更されないことを示すことができます。たとえば、Stringクラスはfinal型クラスです。finalの具体的な使い方はわかっていても、マルチスレッドでのfinalの並べ替えの問題は無視しやすいと思いますので、一緒に議論したいと思います。
第二に、最終的な特定の使用シナリオ
Finalは変数、メソッド、およびクラスを変更できます。つまり、最終使用の範囲は基本的にJavaのすべての場所をカバーします。ロックで変更される位置は次のとおりです:変数、メソッド、およびクラス。
2.1、変数
- Javaの変数は、メンバー変数とメソッドローカル変数に分けることができます。したがって、死角を見逃さないようにするためにも、この方法に従います。
2.1.1最終メンバー変数:クラス変数、インスタンス変数
- 一般に、各クラスのメンバー変数は、クラス変数(静的に変更された変数)とインスタンス変数に分けることができます。
- これら2種類の変数に初期値を割り当てるタイミングは異なります。クラス変数は、変数を宣言するときに、または静的コードブロックで直接初期値を割り当てることができます。一方、インスタンス変数は、変数を宣言するときに割り当てることができます。初期値をに割り当てるインスタンス変数、および非静的初期化ブロックとコンストラクターで初期値を割り当てます。
- クラス変数には初期値を割り当てる機会が2回ありますが、インスタンス変数には初期値を割り当てる機会が3回あります。最終変数が初期化されていない場合、システムは暗黙的な初期化を実行せず、エラーが発生します。
- クラス変数:初期値は、静的初期化ブロックで、またはクラス変数が宣言されたときに指定する必要があり、これら2つの場所のいずれかでのみ指定できます。
- 変数の例:非静的初期化ブロック内にあり、インスタンス変数または指定された初期値コンストラクターを宣言する必要があり、3か所でのみ指定できます。
2.2.2、最終的なローカル変数
最終的なローカル変数は、プログラマーによって明示的に初期化されます。
最終的なローカル変数が初期化されている場合、後で再度変更することはできません。
最終変数が初期化されていない場合は、割り当てることができます。割り当てが1つしかない場合は、割り当てを再度行うとエラーが発生します。
最終的な基本データ型と最終的な参照データ型:
- finalが基本データ型のデータを変更する場合、一度割り当てられると、再度変更することはできません。
- 参照型変数の場合、参照のみを保存し、finalは、参照型変数によって参照されるアドレスが変更されないこと、つまり、オブジェクトが常に参照されることを保証するだけですが、オブジェクトのプロパティは変更できます。
マクロ変数:定数
最終変数の不変性を使用して、次の3つの条件が満たされると、変数は「マクロ変数」、つまり定数になります。
- 最終修飾子を使用して変更します。
- 初期値は、最終変数が定義されるときに指定されます。
- 初期値はコンパイル時に一意に指定できます。
注:マクロ変数がプログラムの他の場所で使用されている場合、コンパイラーはそれを変数の値に直接置き換えます。
2.2。方法
オーバーライドオーバーライド:
- 親クラスのメソッドが最終的に変更された場合、サブクラスは親クラスのメソッドをオーバーライドできません。
- たとえば、Objectでは、getClass()メソッドはfinalであり、このメソッドをオーバーライドすることはできませんが、hashCode()メソッドはfinalによって変更されず、hashCode()メソッドをオーバーライドできます。
過負荷:
finalによって変更されたメソッドはオーバーロードされる可能性があります。(少し考えてみてください、絶対に影響はありません)
2.3クラス
クラスが最終的に変更されると、クラスのテーブル名をサブクラスに継承できなくなります。
親クラスがファイナライズされ、子クラスが親クラスを継承すると、エラーが報告されます。
サブクラスの継承は、親クラスのメソッドをオーバーライドして親クラスのプロパティを変更することが多いため、特定のセキュリティリスクが発生します。したがって、クラスを継承したくない場合は、最終変更を使用できます。
3、最後の例
Finalは、finalの不変性を利用するために、不変クラスとしてよく使用されます。まず、不変クラスとは何かを見てみましょう。
不変クラスとは、このクラスのインスタンスが作成された後、インスタンスのインスタンス変数を変更できないことを意味します。次の条件が満たされると、不変のクラスになる可能性があります。
- プライベート修飾子とfinal修飾子を使用して、クラスのメンバー変数を変更します
- クラスのメンバー変数を初期化するためのパラメーターをコンストラクターに提供します。
- 通常のメソッドはfinaによって変更されたメンバー変数を変更できないため、setterメソッドではなく、このクラスのメンバー変数にのみgetterメソッドを提供します。
- 必要に応じて、ObjectクラスのhashCode()メソッドとequals()メソッドを書き直します.equals()を使用して、同じ2つのオブジェクトのハッシュコード値も等しいことを確認する必要があります。
JDKで提供される8つのラッパークラスとStringクラスはすべて不変のクラスです。Stringの実装を見てみましょう。
/** The value is used for character storage. */
private final char value[];
Stringの値が最終的に変更され、上記の他のプロパティも一貫していることがわかります。
第四に、マルチスレッドでのfinalの適用
上で説明した最終的な使用法は、Javaの基本レベルに属する必要があります。これらを理解した後、私たちは本当に最終的なものをマスターしましたか?複数のスレッドでのfinalの並行性を検討しましたか?
でJavaのメモリモデル、我々は、Javaメモリモデルが彼らの最大の利点を十分に発揮するために、プロセッサおよびコンパイラを可能にするために下側の層には非常にいくつかの制約があることを知っている。それは、Javaメモリモデルが弱い、と言うことです最下層のメモリデータモデル。
同時に、プロセッサとコンパイラは、パフォーマンスを最適化するために、コンパイラとプロセッサを使用して命令シーケンスを並べ替えます。では、マルチスレッドの場合、finalのどのような並べ替えが実行されますか?スレッドセーフの問題が発生しますか?次に、最終的な並べ替えを見てみましょう。
4.1、最終的なドメインの並べ替えルール:基本型、参照型
最終的に変更されたデータ型分類によると:
基本的なデータ型:
- 最終的なドメインの書き込み:書き込みが禁止され、最終的なドメインとリオーダ工法、そのようにオブジェクトがすべてのスレッドに表示されているときことを保証するように、施工方法の外に、最終的なドメインを書き込むことが禁止されています、 、オブジェクトの最終ドメインが初期化されました。
- 最終フィールドの読み取り:オブジェクトの参照を初めて読み取り、オブジェクトに含まれる最終フィールドを並べ替えることは禁止されています。
参照データ型:
追加の制約が追加されます。コンストラクターで最終的に変更されたオブジェクトのメンバーフィールドに書き込み、その後、構築されたオブジェクトの参照を参照変数に割り当てて並べ替えることは禁止されています。
ファイブ、ファイナルの実現原理
上で述べたように、最終ドメインを作成するには、最終ドメインが作成された後、コンストラクターがを返す前に、コンパイラーがStoreStoreバリアを挿入する必要があります。最終ドメインを読み取るための並べ替えルールでは、コンパイラは、最終ドメインを読み取る操作の前にLoadLoadバリアを挿入する必要があります。
X86処理を例にとると、X86は書き込みと書き込みを並べ替えないため、StoreStoreバリアを省略できるのは非常に興味深いことです。以来、間接的依存関係を持つ操作は並べ替えされない、X86のプロセッサに、LoadLoadバリアは、最終的なドメインを読み取るために必要も省略する。つまり、X86を例にとると、最終ドメインの読み取り/書き込みのメモリバリアが省略されます。挿入されるかどうかは、プロセッサによって異なります。