web-dev-qa-db-ja.com

Java finalsはコンパイラがより効率的なバイトコードを作成するのに役立ちますか?

可能性のある複製:
Javaで最後のキーワードを使用するとパフォーマンスが向上しますか?

final修飾子には 異なる結果 Javaを適用する対象に応じて異なります。 ifadditionallyこれは、コンパイラがより効率的なバイトコードを作成するのに役立つかもしれません。

したがって、あなたの専門知識では、次のいずれかを行ってコンパイラを助けますか、それとも通常のJavaの理由でのみ使用しますか?

  • 最終クラス
  • 最終的な方法
  • 最終フィールド
  • 最終的なメソッドの引数

ありがとう!

編集:すべてのあなたの答えをありがとう! @Zohaibが示唆したように、私の質問は this の複製です。投稿する前に十分な検索ができなかった。あなたたちが良い貢献をしたので、私はそれを削除していませんが、答えはマージできます。特に断りのない限り、「クローズの投票」システムに決定を任せます。

42
Miquel

Javaバイトコードコンパイラは通常、最適化の方法でほとんど機能しないため、finalを使用する場合、バイトコードはそれほど効率的ではありません。効率のボーナス(ある場合)は、 JITコンパイラによって生成されたネイティブコード。

理論的には、finalを使用すると、JITコンパイラに最適化に役立つヒントが提供されます。実際には、最近のHotSpot JITコンパイラーは、ヒントを無視することで、より良い仕事をすることができます。たとえば、最近のJITコンパイラは通常、グローバル分析を実行して、指定されたメソッド呼び出しがアプリケーションの現在ロードされているクラスのコンテキストでリーフメソッドの呼び出しであるかどうかを確認します。この分析はfinalヒントよりも正確であり、ランタイムは、分析を無効にする新しいクラスが読み込まれたことを検出し、影響を受けるコードの分析とネイティブコード生成をやり直すことができます。

したがって、ベストプラクティスは、finalを使用して(広義には)設計意図を表現し、必要なその他のセマンティック効果を実現することです。 (たとえば、final修飾子を使用すると、スレッドセーフな不変型の実装で重要な役割を果たす可能性があります。 JLS 17.5 を参照してください)最適化のヒントとしてfinalを使用すると、あまり達成できず、コードの変更や拡張が難しくなります。

[〜#〜]更新[〜#〜]

これにはいくつかの例外があります(以下で指摘)。

  • 特定の状況では、フィールドをfinalとして宣言すると、バイトコードコンパイラがフィールドを処理する方法が変わります。上記の例を挙げました。もう1つは、「定数変数」の場合( JLS 4.12.4 )で、static finalフィールドの値になります現在のクラスと他のクラスの両方でバイトコードコンパイラによってインライン化されます。これにより、コードの動作に影響が及ぶ可能性があります。 (たとえば、定数変数を参照してもクラスの初期化はトリガーされません。したがって、finalmayを追加すると、クラスの初期化の順序が変更されます。)

  • フィールドまたはローカルパラメーターをfinalとして宣言すると、他の方法では実行できない小さなJITコンパイラーの最適化が可能になると考えられます。ただし、finalとして宣言できるフィールドcouldも、JITコンパイラーによって事実上finalであると推測されます。 (JITコンパイラーが実際にこれを行うこと、およびそれが生成されたネイティブコードに影響を与えるかどうかは明確ではありません。)

ただし、私の以前のアドバイスが適用されます。最適化のヒントとしてではなく、finalを使用して設計意図を表現します。

60
Stephen C

その質問はすでにかなり多く尋ねられており、答えは一般にあります:コンパイラーはいくつかの最適化(たとえば、最終的な静的フィールドであるインライン定数)を行う可能性がありますが、これらのパフォーマンスの向上は実際には目立たない可能性があるため、一般にこれを気にする必要はありません。 「通常」のJavaの理由でfinalキーワードを使用するだけです(フィールドまたはパラメーターを不変にし、サブクラス化やメソッドのオーバーライドを防止します)。

11
Thomas

コードでテストすることをお勧めします。場合によっては、コンパイラに違いをもたらす可能性がありますが、JITに違いが生じる可能性が高くなります。マイクロベンチマークとマイクロチューニングに関して言えば、違いを生むべきものと実際に違いを生むものとは同じではないことがよくあり、確実な方法は良いテストだけです。

もう1つの問題は、JVMが常に改善されており、以前は大きな違いをもたらしたトリックが適用されなくなる可能性があることです。例えばJava 5.0 Locksynchronizedよりもはるかに高速でしたが、Java 6では差がはるかに小さく、synchronizedの方が高速です。

一般に、コードをシンプル、明確、簡単に保守できるようにすることをお勧めします。これにより、コードが効率的になります。

6
Peter Lawrey