52

Java 言語のドキュメントには次のように書かれています。

プリミティブ型または文字列が定数として定義されていて、その値がコンパイル時にわかっている場合、コンパイラはコード内のすべての定数名をその値に置き換えます。これは、コンパイル時定数と呼ばれます。

私の理解では、コードがある場合は次のようになります。

private final int x = 10;

次に、コンパイラはx、コード内のすべての出現箇所をリテラルに置き換え10ます。


ただし、実行時に定数が初期化されるとします。

private final int x = getX(); // here getX() returns an integer value at run-time.

コンパイル時の定数と比較して、パフォーマンスが低下することはありますか (無視できる程度であっても)?


別の質問は、以下のコード行かどうかです。

private int y = 10; // here y is not final

コンパイラによってコンパイル時定数と同じように扱われますか?


最後に、回答から私が理解していることは次のとおりです。

  1. final staticコンパイル時の定数を意味します
  2. 定数であることを意味しますfinalが、実行時に初期化されます
  3. static実行時に初期化されることを意味します
  4. withoutfinalは変数であり、定数として扱われません。

私の理解は正しいですか?

4

8 に答える 8

63

コンパイル時定数は次のとおりです。

  • 最終宣言
  • プリミティブまたは文字列
  • 宣言内で初期化
  • 定数式で初期化

だからprivate final int x = getX();一定ではありません。

2 番目の質問private int y = 10;は一定ではない (この場合は非最終) ため、オプティマイザーは値が将来変更されないことを確認できません。したがって、定数値ほど最適化することはできません。答えは: いいえ、コンパイル時定数と同じようには扱われません。

于 2012-01-31T16:21:11.197 に答える
3

JLSによると、「定数変数」が静的である必要はありません。

したがって、「定数変数」は静的または非静的(インスタンス変数)の可能性があります。

しかし、JLS は、変数が「定数変数」であるための他のいくつかの要件を課しています (単に最終的なものであることに加えて):

  • 文字列またはプリミティブのみである
  • final であり、空白の final は許可されていないため、インラインのみで初期化されます
  • "constant expression" = "compile-time constant expression" で初期化 (以下の JLS の引用を参照)

4.12.4. 最終変数 (JLS)

定数変数は、定数式(§15.28)で初期化されるプリミティブ型または型 Stringの最終変数です。

15.28. 定数式

コンパイル時の定数式は、プリミティブ型の値を示す式、または突然完了しない String であり、以下のみを使用して構成されます。

プリミティブ型のリテラルと String 型のリテラル (§3.10.1、§3.10.2、§3.10.3、§3.10.4、§3.10.5)

プリミティブ型へのキャストと String 型へのキャスト (§15.16)

単項演算子 +、-、~、および ! (ただし、++ または -- は除く) (§15.15.3、§15.15.4、§15.15.5、§15.15.6)

乗法演算子 *、/、および % (§15.17)

加算演算子 + および - (§15.18)

シフト演算子 <<、>>、および >>> (§15.19)

関係演算子 <、<=、>、および >= (ただし、instanceof は除く) (§15.20)

等価演算子 == および != (§15.21)

ビット演算子と論理演算子 &、^、および | (§15.22)

条件 AND 演算子 && および条件 OR 演算子 || (§15.23、§15.24)

三項条件演算子 ? : (§15.25)

含まれる式が定数式である、括弧で囲まれた式 (§15.8.5)。

定数変数 (§4.12.4) を参照する単純な名前 (§6.5.6.1)。

TypeName 形式の修飾名 (§6.5.6.2)。定数変数を参照する識別子 (§4.12.4)。

于 2018-01-26T11:31:29.853 に答える
1

一部のマシンでは、少なくとも1つのメソッド呼び出しが必要になるため(これはコンパイル時の定数ではないという事実に加えて)、パフォーマンスが非常にわずかに低下する可能性がありますが、あなたが言ったように、それは無視できるので、なぜわざわざ?private final int x = getX();

2 番目の質問についてyは、実行時に変更される可能性があるため、最終的なものではないため、コンパイル時の定数ではありません。

于 2012-01-31T16:21:21.220 に答える
1

このfinalキーワードは、変数が一度だけ初期化されることを意味します。実定数も宣言する必要がありstaticます。したがって、どの例もコンパイラによって定数として扱われません。それにもかかわらず、 final キーワードは、変数が (コンストラクター内または文字どおりに) 1 回だけ初期化されることを (およびコンパイラーに) 伝えます。コンパイル時に値を割り当てる必要がある場合は、フィールドを静的にする必要があります。

パフォーマンスはそれほど影響を受けませんが、プリミティブ型は不変であることに注意してください。一度作成すると、ガベージ コレクターによって削除されるまでその値がメモリに保持されます。したがって、変数がy = 1;あり、それをy = 2;メモリ内に変更すると、JVM は両方の値を持ちますが、変数は後者を「指します」。

プライベート int y = 10; // ここで y は最終的なものではありません

コンパイラによってコンパイル時定数と同じように扱われますか?

いいえ。これはインスタンス変数であり、実行時に作成、初期化、使用されます。

于 2012-01-31T17:02:57.643 に答える
0

private final int x = getX(); オブジェクトが初めて宣言されたときに呼び出されます。パフォーマンスの「低下」は依存しますgetX()が、それはボトルネックを作成するようなものではありません.

于 2012-01-31T16:21:59.713 に答える