最終クラス
クラスが最終クラスとして定義されている場合、クラスは他のクラスで継承できないことを意味します。つまり、拡張後に使用できません。それ以外の場合は、コンピレーション中にエラーが発生します。
パッケージcom.iderzheng.finalkeyword;パブリックファイナルクラスのfinalclass {} //エラー:finalclass packageclassから継承することはできませんfinalclass {} Javaは、クラスの定義を最終的なものとしてサポートしています。これは、オブジェクト指向プログラミングの基本原則に違反しているようです。ただし、一方で、囲まれたクラスは、クラスのすべての方法が固定されており、動的にロードされるサブクラスのオーバーライドがないことも保証します。これにより、コンパイラが最適化する可能性が高まります。最良の例は文字列です。これは最終クラスです。 Javaコンパイラは、ストリング定数(二重引用符に含まれるもの)を直接文字列オブジェクトに変換し、同時にオペレーター +操作を新しい定数に直接最適化できます。最終的な変更により、サブクラスがスプライシング操作に異なる値を返すことができるためです。
すべての異なるクラス定義 - トップレベルのクラス(グローバルまたはパッケージが表示)では、ネストされたクラス(内部または静的ネストクラス)を最終的に変更できます。ただし、一般に、ファイナルは、グローバル以外のクラスでは、アクセス修飾子が可視性を制限しており、これらのクラスを継承することはすでに困難であるため、最終的な制限の層を追加する必要はないため、ファイナルはパブリックとして定義されたクラスを変更するために主に使用されます。
また、匿名のクラスを継承することはできませんが、コンパイラによるファイナルに限定されないことも言及されています。
java.lang.reflt.Modifierをインポートします。 public class main {public static void main(string [] args){runnable anonymous = new runnable(){@override public void run(){}}; System.out.println(modifier.isfinal(anonymous.getClass()。getModifiers())); }}出力:
間違い
最終的な方法
継承の概念に密接に関連しているのは多型であり、これにはオーバーライドと隠れの概念の違いが含まれます(利便性のために、以下は集合的に「書き換え」と呼ばれます)。ただし、C ++のメソッド定義とは異なり、仮想キーワードがサブクラスに追加されているかどうか、サブクラスの署名の方法が上書きまたは非表示になっていても、Javaでは、同じメソッド署名を使用して親クラスメソッド(静的メソッド)を形成し、オブジェクトメソッド(非静的方法)を形成します。 Javaはオブジェクトを介してクラスメソッドに直接アクセスできるため、Javaはクラスメソッドとオブジェクトメソッドが同じクラスで同じ署名を持つことを許可しません。
最終クラスは、クラス全体を継承できないことを定義しており、クラス内のすべての方法をサブクラスでカバーして隠すことができないことも意味します。クラスが最終的に変更されていない場合、これらのメソッドがサブクラスによって書き換えられないように、ファイナルを使用していくつかの方法を変更できます。
同様に、このような設計はオブジェクト指向の多型を破壊しますが、最終的な方法はその実行の決定論を確保し、メソッド呼び出しの安定性を保証することができます。一部のフレームワーク設計では、いくつかの抽象クラスの方法は、フレームワークの一部のドライバーコードが確立された目標を達成するためにこれらの方法に依存するため、それをカバーするサブクラスはありません。
次の例は、さまざまなタイプの方法における最終的な変更の役割を示しています。
パッケージcom.iderzheng.other; public class finalMethods {public static void publicstaticmethod(){} public final void publicFinalMethod(){} public static final void publicStaticFinalMethod(){}保護された最終Void ProtectedFinalMethod(){} Protected Static Final vioid finalmethod { void staticfinalmethod(){} private static final vaid privatestaticfinalmethod(){} private final void privatefinalmethod(){}}パッケージcom.iderzheng.finalkeyword; com.iderzheng.other.finalmethodsをインポートします。パブリッククラスのメソッドはfinalMethods {public static void publicstaticmethod(){} //エラーを拡張します:パブリックファイナルvoid publicfinalmethod(){} //エラーをオーバーライドできませんパブリックスタティック最終void publicstaticfinalmethod(){} //エラーstatic final void publicStaticFinalMethod(){} //エラー:保護された最終voidプロテクタントファイナルメソッド(){} //エラーをオーバーライドできません。 privatestaticFinalMethod(){}プライベート最終void privateFinalMethod(){}}まず、上記の例では、finalmethodsとメソッドは異なるパッケージの下で定義されていることに注意してください。最初のpublicStaticMethodでは、サブクラスは親クラスの静的方法を正常に書き換えますが、それが静的な方法であるため、実際に何が起こるかは実際に「隠されています」です。具体的には、methods.publicstaticmethod()を呼び出して、メソッドクラスで実装を実行します。 finalmethods.publicstaticmethod()を呼び出すと、実装はサブクラスの多型荷重では発生しませんが、finalmethodsの実装を直接使用します。したがって、サブクラスを使用してメソッドにアクセスする場合、親クラスによって署名されたメソッドの可視性が非表示になります。
最終的な変更方法で説明されているように、グローバルな方法PublicFinalMethodの場合、サブクラスはそれを上書きすることを禁じられており、コンパイル時に例外がスローされます。ただし、メソッド名はサブクラスで同じですが、次のようなパラメーターがあります:publicFinalMethod(String x)はOKです。これは同期メソッドの署名であるためです。
Intellijでは、IDEはPublicStaticFinalMethodへの警告を示しています:「静的」メソッドは「最終」と宣言されています。それは冗長であるように思われますが、例から、最終的には静的な方法からサブクラスの定義を禁止してそれを隠すことが禁止されていることがわかります。実際の開発では、サブクラスと親クラスの同じ静的方法を定義する動作は非常に望ましいです。なぜなら、隠された方法は、開発者が異なるクラス名を使用して異なる効果を定義することに注意を払う必要があるため、エラーを引き起こしやすいためです。さらに、クラス内では、クラス名を使用せずに静的メソッドを直接呼び出すことができます。開発者が再び継承するとき、彼は隠された存在に気付かないかもしれません。デフォルトでは、親クラスの方法を使用する場合、彼はそれが期待される結果ではないことがわかります。したがって、静的メソッドはデフォルトで最終的になり、非表示にすべきではないので、IDEはそれが不必要な変更であると考えています。
親クラスの保護された変更と公開修正方法はサブクラスに表示されるため、保護された方法の最終的な変更の状況は、パブリックメソッドの状況と同じです。実際の開発では、そのような方法があまりにも実用的であるため、保護された静的方法は一般にめったに定義されないことに言及する必要があります。
親クラスパッケージ方法の場合、異なるパッケージの下のサブクラスは見えません。プライベート方法はカスタマイズされており、親クラスのみがアクセスできます。そのため、コンパイラを使用すると、サブクラスが同じ方法を定義できます。しかし、親クラスはサブクラスの書き換えによってはなく、修飾子を通してこれらの方法を非表示にしたため、これはオーバーライドまたは非表示になりません。もちろん、サブクラスと親クラスが同じパッケージにある場合、状況は以前の公衆と保護されたものと同じになります。
最終的な方法が効率的なのはなぜですか?
最終的な方法では、埋め込みメカニズムを使用して、コンピレーション中にインラインを最適化します。インライン最適化とは、実行時に関数を呼び出すのではなく、コンピレーション中に関数コードの交換を直接呼び出すことを指します。インラインは、コンパイル時に最終的に使用する機能を知る必要があります。明らかに、ファイナルなしでそれを使用することはできません。非ファイナル方法は、サブクラスで書き換えられる場合があります。多型の可能性があるため、コンパイラは、コンピレーション段階で将来的にメソッドを呼び出すオブジェクトの真のタイプを決定することができず、どの方法を呼び出すかを決定することはできません。
最終変数
簡単に言えば、Javaの最終変数は1回のみ初期化する必要があり、変数は値にバインドされます。ただし、この割り当ては、変数が定義されているときにすぐに初期化する必要はありません。 Javaは、条件付きステートメントを通じて最終変数のさまざまな結果もサポートしていますが、変数はいずれにしても1回しか割り当てられません。
ただし、Javaのオブジェクト変数は参照値のみであるため、Javaの最終変数は絶対定数ではないため、最終的には参照を変更できず、オブジェクトのコンテンツを変更できます。 C/C ++ポインターと比較して、Type * const Variableよりもタイプ * const変数に似ています。
Java変数は、ローカル変数(ローカル変数)とクラスメンバー変数(クラスフィールド)の2つのカテゴリに分類できます。以下は、初期化の状況を個別に導入するためのコードです。
ローカル変数
ローカル変数は、主にメソッドで定義されている変数を指します。それらは消え、メソッドの後にアクセスできなくなります。関数パラメーターに分けることができる特別なケースがあります。この場合、その初期化は、関数が呼び出されたときに渡されたパラメーターに拘束されます。
他のローカル変数の場合、それらはメソッドで定義されており、その値は条件付きで初期化できます。
public String Method(final boolean finalparam){//エラー:最終パラメーターfinalparamに割り当てられない場合があります// finalParam = true; Final Object Finallocal = finalParam? new object():null; Final Int FinalVar; if(finallocal!= null){finalvar = 21; } else {finalvar = 7; } //エラー:可変finalvarはすでに割り当てられている可能性があります// finalvar = 80;最終文字列finalRret; switch(finalvar){case 21:finalRret = "me";壊す;ケース7:finalRret = "he";壊す;デフォルト:finalRret = null; } finalRret;}上記の例から、最終的に変更された関数パラメーターに新しい値を割り当てることはできませんが、他の最終ローカル変数に条件文の値を割り当てることができます。これにより、ファイナルに特定の柔軟性も提供されます。
もちろん、条件ステートメントのすべての条件には、最終的なローカル変数への割り当てを含める必要があります。そうしないと、変数が初期化されない可能性があるというエラーが表示されます。
public String Method(final object finalparam){final int finalvar; if(finalparam!= null){finalvar = 21; } final String finalRret; //エラー:可変finalvarは初期化されたスイッチ(finalvar){case 21:finalRret = "me";壊す;ケース7:finalRret = "he";壊す; } //エラー:変数finalRretが初期化されたfinalRret;}理論的には、ローカル変数は最終的なものとして定義する必要はなく、合理的な設計方法はローカル変数を適切に維持できるはずです。匿名関数を使用してJavaメソッドで閉鎖を行う場合、Javaは参照されるローカル変数を最終的に定義する必要があることを要求します。
public Runnableメソッド(String String){int integer = 12; new runnable(){@override public void run(){//エラー:final system.out.println(string)を宣言する必要があります。 //エラー:最終system.out.println(integer)を宣言する必要があります。 }};}クラスフィールド
クラスのメンバー変数は、実際には静的と非静的な2つのタイプに分割できます。静的クラスのメンバー変数の場合、それらはクラスに関連しているため、定義時に直接初期化されることに加えて、静的ブロックに配置することもでき、後者を使用すると、より複雑なステートメントを実行できます。
パッケージcom.iderzheng.finalkeyword; Import java.util.hashset; import java.util.linkedhashset; import java.util.set;パブリッククラスStaticFinalfields {Static final int static_final_init_inline = 7;静的最終セット<integer> static_final_init_static_block; / ** static block **/ static {if(system.currenttimemillis()%2 == 0){static_final_init_static_block = new Hashset <>(); } else {static_final_init_static_block = new linkedhashset <>(); } static_final_init_static_block.add(7); static_final_init_static_block.add(21); }}また、Javaには非静的なメンバー変数を初期化できる非静的ブロックもありますが、これらの変数については、しばしば初期化のためにコンストラクターに配置されます。もちろん、各最終変数がコンストラクターで1回初期化されるようにする必要があります。これを介して他のコンストラクターが呼び出された場合、これらの最終変数はコンストラクターに割り当てられなくなります。
パッケージcom.iderzheng.finalkeyword;パブリッククラスfinalfields {final long final_init_inline = system.currenttimemillis(); final long final_init_block; final long final_init_constructor; / **初期ブロック**/ {final_init_block = system.nanotime(); } finalfields(){this(217); } finalfields(boolean bool){final_init_constructor = 721; } finalfields(long init){final_init_constructor = init; }}クラス(クラス)とメソッド(方法)の変更に最終を使用すると、主にオブジェクト指向の継承に影響します。継承がなければ、親クラスのサブクラスのコードに依存することはありません。したがって、メンテナンス中にコードを変更する場合、サブクラスの実装が破壊されるかどうかを検討する必要はありません。これにより、より便利になります。変数で使用されると、Javaは変数値が変更されないようにします。さらに設計がクラスのメンバーを変更できないことを保証すると、変数全体を定数に変えることができます。これは、マルチスレッドプログラミングに非常に有益です。したがって、ファイナルはコードメンテナンスに非常に良い影響を及ぼします。