きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

Javaにおける定数

「定数」という言葉の定義が意外と曖昧ではないだろうかと昔から思っていた。
「定数はstatic finalで宣言する」というマニュアル的な表現に疑問を思ってきた。

「static final宣言したものは、定数とは限らない」

  static final String A;
  static{
    A = "HOGE"
  }

この場合のAは、定数ではない。
次の場合のAも、定数ではない。

  static final String A = getA();
  private static String getA(){
    return "HOGE";
  }

Java Language Specification 3rd Editionに、明確な表現を見つけた。
4.12.4 final Variablesの箇所にある。

We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16).

compile-time constant expression(コンパイル時定数式?)というのが重要だ。
定数とは、finalでかつ定数式で初期化されたものをを言う。
また、その型はprimitive型かString型である。

15.28 Constant Expression


ConstantExpression:
Expression
A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

Literals of primitive type and literals of type String (§3.10.5)
Casts to primitive types and casts to type String
The unary operators +, -, ~, and ! (but not ++ or --)
The multiplicative operators *, /, and %
The additive operators + and -
The shift operators <<, >>, and >>>
The relational operators <, <=, >, and >= (but not instanceof)
The equality operators == and !=
The bitwise and logical operators &, ^, and |
The conditional-and operator && and the conditional-or operator ||
The ternary conditional operator ? :
Parenthesized expressions whose contained expression is a constant expression.
Simple names that refer to constant variables (§4.12.4).
Qualified names of the form TypeName . Identifier that refer to constant variables (§4.12.4).

Compile-time constant expressions are used in case labels in switch statements (§14.11) and have a special significance for assignment conversion (§5.2). Compile-time constants of type String are always "interned" so as to share unique instances, using the method String.intern.
A compile-time constant expression is always treated as FP-strict (§15.4), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.

リテラルという言葉があるが、nullもリテラルだが上記にnullは含んでない。


定数はstaticである必要性は言語上はない。


リテラル(null除く)を代入する変更しない変数はfinal宣言する」という方が自分には馴染む。


コンパイラは、重複した文字をちゃんと1つの実体にしてくれているので、
コンスタントプールに同じ文字が出てくることもない。
昔は違ったのかもな。


non-staticメソッドから使う定数ですらstatic final宣言する必要があるのだろうか?
変数スコープを広げすぎじゃないのかなとか、
クラスの持つべき属性なのか、
インスタンスが持つべき属性なのか、いろいろ思うところがある。