私の推測では、フィールドはプリミティブ型またはのいずれかString
であり、コンパイル時の定数式で初期化されています。
定数式で初期化された static final フィールド (およびそのようなフィールドのみ) の場合、クラスの初期化を引き起こす static フィールドを経由するのではなく、フィールドを参照するすべてのコードに定数値が組み込まれます。ただし、「定数式」の部分は重要です。これは、小さなテスト アプリで確認できます。
class Fields {
public static final String CONSTANT = "Constant";
public static final String NON_CONSTANT = new String("Non-constant");
static {
System.out.println("Initializing");
}
}
public class Test {
public static void main(String arg[]) {
System.out.println(Fields.CONSTANT);
System.out.println(Fields.NON_CONSTANT);
}
}
出力は次のとおりです。
Constant
Initializing
Non-constant
定数フィールドへのアクセスには初期化は必要ありませんが、非定数フィールドへのアクセスには初期化が必要です。final 以外のフィールドを使用しても同じ効果があります。基本的に、定数としてカウントされなくなります。
「これは定数です」という情報は、フィールドを宣言するクラスに組み込まれます。たとえば、javap -c Fields
次の 2 つのフィールドが表示されます。
public static final java.lang.String CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String Constant
public static final java.lang.String NON_CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
フィールド メタデータから欠落しているフィールド メタデータのConstantValue
部分に注意してください。CONSTANT
NON_CONSTANT
定数式を構成する要素の詳細については、JLS のセクション 15.28 を参照してください。
JLS のセクション 12.4.1 は、クラスがいつ初期化されるかを指定します。
クラスまたはインターフェイスの型 T は、次のいずれかが最初に発生する直前に初期化されます。
T はクラスであり、T のインスタンスが作成されます。
T はクラスであり、T によって宣言された静的メソッドが呼び出されます。
T によって宣言された static フィールドが割り当てられます。
T によって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません (§4.12.4)。
T は最上位クラス (§7.6) であり、T (§8.1.3) 内で語彙的にネストされた assert ステートメント (§14.10) が実行されます。
(私のものを強調してください。)