固定(不変)の値を表すのが定数。
Javaで定数値(固定の値、即値)を表現するには、以下のようにする。[2003-07-06]
リテラル名 | 形式 | 型 | 例 |
---|---|---|---|
整数リテラル | 数 ・「0」で始めると八進数 ・「0x」で始めると十六進数 ・「0b」で始めると二進数(JDK1.7以降)[2012-01-14] |
int | 123 |
・末尾にLを付けるとlong型 | long | 123L |
|
浮動小数リテラル | 小数点付きの数 | double | 123.0 |
eを使う書き方。mEnはm×10n [2019-12-08] | 1.23e10 |
||
十六進浮動小数点リテラル。hPnはh×2n(JDK1.5以降)[2019-12-08] | 0x1.23p2 |
||
・末尾にFを付けるとfloat型 ・末尾にDを付けるとdouble型 |
float double |
123f |
|
文字リテラル | シングルクォーテーションで囲む。 | char | 'A' |
文字列リテラル | ダブルクォーテーションで囲む。 | String | "abc" |
論理値リテラル | true又はfalse | boolean | true |
空リテラル | null | 空型 | null |
JDK1.7では、数値リテラルの途中でアンダーバーを入れられるようになった。[2012-01-14]
int n = 123_456; int n = 0b111_10111; × int n = _123; //先頭に付けると変数扱いになるのは今まで通り × int n = 123_; //末尾に付けるのも駄目
文字 | コード | 機能 | 備考 | 関連 |
---|---|---|---|---|
\b | 08 | バックスペース | back space | |
\f | 0C | 改ページ | form feed | |
\n | 0A | 改行 | new line/line feed | →マシン非依存の改行コードの取得方法 |
\r | 0D | 復帰(行頭にカーソルを戻す) | carriage return | |
\t | 09 | 水平タブ | horizontal tab | |
\\ | 5C | 「\」 | ||
\' | 2C | 「'」 | ||
\" | 22 | 「"」 | ||
\ooo | 3桁の八進数(000〜377) | octal |
文字 | コード | 機能 | 備考 | 関連 |
---|---|---|---|---|
\uhhhh | 4桁の十六進数(0000〜FFFF) | hexadecimal | \uはコンパイルの第一段階(字句解析)で解釈されるので、 エスケープシーケンスとは動作が異なる。 |
エスケープシーケンスとUnicodeエスケープは似て非なるもの。[2008-08-30]
→処理の差異
finalで宣言して初期値を与えた変数は、定数として扱える。[2008-06-22]
なお、定数として扱う場合は、変数名は全て大文字にするのが慣例。
public static final int BASE_YEAR = 1970;
この変数には後から値を代入することが出来ない。(finalが付いていると、代入できなくなる)
代入できない→値が不変(固定)→定数
ただし、オブジェクト(参照型)の場合は、必ずしも固定(不変)というわけではない。
final Map SAMPLE_MAP = new HashMap();
変数SAMPLE_MAPには新しいMapを代入することは出来ない。しかしSAMPLE_MAP内に値をセットするのは自由。
SAMPLE_MAP.put("key", "value"); //←問題なし SAMPLE_MAP = new HashMap(); //←これはコンパイルエラーになる
つまり、変数にfinalを付けた場合、あくまでその変数への代入が出来なくなるだけ。
その変数(のクラス)のメソッドやフィールドには普通にアクセスできる。
(すなわち、「finalが付いている」からと言って「不変」というわけではない。この場合は「定数」とは呼び難いので、大文字の変数名にはしない方がいいかも)
StringやInteger等の変更不可能なオブジェクトの場合は、間違いなく定数となる。
final String STR = "abc"; final Integer NUMBER = new Integer(1234);
オブジェクトの定数を返すメソッドを作りたい場合は注意が必要。
定数(固定)のつもりで不変でないクラスのオブジェクトを返すと、それが変更されない保証は無い。
class Empty { private static final List EMPTY_LIST = new ArrayList(0); public List getList() { return EMPTY_LIST; } }
Empty empty = new Empty(); List list1 = empty.getList(); list1.add("abc"); List list2 = empty.getList(); System.out.println(list2.size());
このgetList()は、用意しておいた空のリストを返している。
しかしその内容は、呼んだ元が書き換えることが出来る。(書き換えることを阻止できない)
したがって、書き換えられてしまった場合、二度目以降の呼び出しでは、空のリストという役を果たしていない…。
C++では(finalに相当する)constキーワードを使って、呼び出した側で値を変更できないように関数(メソッド)定義側で指定できた。
public: const List* getList() { return EMPTY_LIST; }
const List* list1 = s.getList(); list1->add("abc"); ←「constオブジェクトは変更できない」というコンパイルエラー
Javaで同じように(constに相当する)finalを付けてみると…
public final List getList() { 〜 }
そのメソッドはオーバーライドできないという意味になってしまう(苦笑)
→空のコレクション(EMPTY_LISTやEMPTY_MAP) [2008-07-09]
→内容も変更できないコレクション(ListやMap)の作り方 [2008-07-09]
static finalで定義した変数は定数として使えるので、switch文でも使用できる。[2010-03-06]
のではあるが、値の初期化の仕方によっては使うことが出来ない。
static final int S1 = 1; static final int S2; static final int S3 = func(); //メソッド呼び出しによる初期化 static { //静的初期化子による初期化 S2 = 2; } static int func() { return 3; }
int n = 〜; switch (n) { case S1: System.out.println("S1"); break; case S2: System.out.println("S2"); break; case S3: System.out.println("S3"); break; default: System.out.println("def"); break; }
case S1は問題ないが、case S2とS3はコンパイルエラーとなる。
S1は変数宣言と同時に初期値を指定しているので、定数として使用できる。
S2,S3は変数宣言時には初期値が無いので、実行時にクラスがロードされて初期化処理が実行されるまで値が定まらない。
switch文の定数はコンパイル時には定まっていないといけない(と思われる)ので、初期値指定の無いstatic final変数はcaseに指定できない。
S2の初期化方法(final宣言をしているが初期値は与えず、静的初期化子によって初期化する)は、finalの特徴を示している。
C言語/C++におけるconstはまさに「定数」を示すものだが、Javaのfinalは「変更できない」ことを意味する。
つまり、どこかで一度だけ初期化できるが、後からその値を変更することが出来ない。
初期化している箇所がどこにも無いとコンパイルエラーになる。
(staticフィールドの場合は静的初期化子、staticでないフィールドの場合はインスタンス初期化子やコンストラクター、ローカル変数の場合は使用するまでに初期化する必要がある)
(実行時は、初期化されるまでの間は便宜的にその型のデフォルト値(プリミティブ型の場合は0、参照型の場合はnull)が入っている)
Javaでは以下のような定数が定義されており、使用することが出来る。[2003-07-06]
リテラル名 | 定数名 | 説明 |
---|---|---|
論理値リテラル | true | booleanの値。「真」を表す。 |
false | booleanの値。「偽」を表す。 | |
空リテラル | null | オブジェクトのインスタンスが無い状態を表す。 |
true, false, nullはリテラル(定数)であって、キーワード(予約語)ではないのだそうだ。[/2007-11-13]
すなわち、true,false,nullはコンパイラーが特殊扱いしているのではなく、暗黙にライブラリーによって(?)final変数(定数)として定義されている、ということ。
その証拠に「null = 0;
」や「true = false;
」といった代入文をJDK1.4やJDK1.5のjavacでコンパイルしてみると、「final
変数 true に値を代入することはできません。」というコンパイルエラーになる。
(「int if;
」といった予約語を使ったコーディングは別のコンパイルエラーになる)
ちなみにtrue, falseの型は言わずと知れたbooleanだが、nullは空型(null型)と言うんだそうだ。[2008-04-08]
Javaはマルチプラットフォーム対応を標榜している。[2007-02-08]
そこで、プログラムを実行する/稼動させるマシン(環境)によって変わる値を取得する方法が用意されている(ものもある)。
概要 | 取得方法 | Windowsの値 | UNIXの値 |
---|---|---|---|
改行コード [/2012-04-12] | System.getProperty("line.separator") |
"\r\n" |
"\n" |
ディレクトリ・ファイル名のパス区切り | File.separator System.getProperty("file.separator") |
"\\" |
"/" |
パスの区切り(PATHやCLASSPATH等) | File.pathSeparator |
";" |
":" |
システムプロパティー(System#getProperty())でしか取得できない値は、定数として宣言しておくと便利かも。
/** * 改行コード */ public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String LINE_SEPARATOR = System.lineSeparator
(); //JDK1.7以降