2.6 変数と型
2.6.1 情報を保存する
プログラミングでは、与えられた情報を定められた手順で分析、加工して出力するということが基本原理になっています。その過程で、必要な情報を保存することは極めて重要です。ここで言う保存とは、記録ディスクにファイルを保存することではありません。計算用の一時的な数値情報をいちいち動作速度の遅い記録装置に保存していては、プログラムは遅くて使い物にならなくなってしまうでしょう。
通常、プログラムが稼動中に必要な情報を保存する時は、主記憶装置に対して入出力が行われます。もちろん、Java はどこでも動くという思想から、プログラマが実装システムの記録装置を意識する必要がないように設計されているので、主記憶装置の扱いを意識する必要はありません。
Java 言語にかぎらず、プログラム言語では何らかのデータを保存するには変数を使います。変数とは、主記憶装置の記録場所の代名詞のような存在で、プログラマはこの変数に情報を保存したり、保存した情報を引き出したりすることができます。
情報の保存にはもう 1 つ大きな問題があります。「2.3 字句変換とUnicode」で説明したように、コンピュータの世界では文字も数値と関連付けられて管理されています。保存されている情報が計算用の数値なのか、表示する文字なのかをどのように識別するべきでしょうか。
機械語レベルで考えれば、それは開発者の自己責任となります。保存されている情報を数値として扱っても、文字として表示してもかまいません。ですが、性質的にまったく異なる情報なので、うっかり数値用の情報を文字として表示してしまった場合、まともな結果を得られることはなく、ひどいバグとなるでしょう。そして、人間はそういったミスを犯す動物です。
幸い、Java 言語は保存された情報、すなわち変数が数値として保存されているのか、文字として保存されているのかといった管理を行ってくれます。そして、この管理を行うための情報を型と呼びます。
例えば「この変数は数値型である」というように表現します。数値型の情報は、数値として扱われなければならず、文字として扱われようとした場合はコンパイラがエラーを発生してくれる仕組みになっているのです。これで、プログラマはつまらないミスから解放されるのです。これを Java 言語の設計者たちは仕様書の中で「Java は強く型付けされた言語である」と表現しています。
2.6.2 ローカル変数宣言文
変数を利用するには、まず、メソッド内でローカル変数宣言文を使います。ローカルとは、メソッド内で宣言された局所的な変数という意味です。ローカル変数はメソッド内でしか宣言することができず、メソッドが終了すると破棄されます(3.7.2 ローカル変数の寿命 参照)。
開発者が意識しなければならないことの 1 つとして、記憶領域は特定のアプリケーションのものではありません。オペレーティング・システムや Java 仮想マシン、他のアプリケーションも利用しているのです。アプリケーションが記憶領域の一部を占有する場合は、「これから、ここを使いますよ~」と宣言しなければならないのです。ローカル変数宣言文は、一般に次のような形になります。
型 変数名;
ローカル変数宣言文はセミコロン ; で終了します。型には、先ほど説明したように、変数に格納されている情報がどのような目的に使用されるものなのかを表すための型情報を指定するキーワードを指定します。変数名には、宣言する変数の新しい識別子を指定します。この識別子は、他の変数識別子と重複することはできず、常に一意のものでなければなりません。変数宣言で指定する型を以下に表します。
キーワード | ビット数 | 型 | 範囲 |
---|---|---|---|
byte | 8 | 整数型 | -128~127 |
short | 16 | -32768~32767 | |
int | 32 | -2147483648~2147483647 | |
long | 64 | -9223372036854775808~9223372036854775807 | |
char | 16 | Unicode 文字 | \u0000~\uFFFF (0~65535) |
float | 32 | 単精度浮動小数点 | -3.4E38~+3.4E38 |
double | 64 | 倍精度浮動小数点 | -1.7E308~+1.7E308 |
boolean | -- | 論理量 | true または false |
情報を保存する時には、情報のサイズが問題となります。16桁の2進数で表現できる情報を64桁の2進数を使って保存するのは冗長ですし、32桁の2進数で表現される情報を、8桁の2進数で表現することは不可能です。どのようなシステムでも記憶装置が保存できる情報量には限界があります。開発者は有限の記憶領域を上手に使わなければならないのです。
8桁の2進数、すなわち1バイトで保存可能な情報であれば byte 型の変数を宣言して保存するべきですし、大きな数字を扱う場合は long 型を用いるべきでしょう。同じ数値を保存する場合でも、このように数値の範囲によって適切な型を選択しなければなりません。
float や double は浮動小数点型で、非整数の計算を行いたいときに利用されます。Java の浮動小数は IEEE 754 標準に従って表現されます。IEEE 754 は 1985 年に浮動小数点演算の国際標準を定めたものです。浮動小数について詳しく説明すると情報科学にずれ込むので、この場では避けることにします。浮動小数点型は小数を含む計算を行うときに使う型であるとだけ覚えておけばよいでしょう。
boolean 型は数値ではなく、二者択一の情報を表現するために利用されます。これについては「2.7 リテラル」及び第3章で詳しく説明します。
この他に、キーワードではありませんが String 型が存在します。String は Java 言語が定めているキーワードではなく、Java の標準クラスライブラリが提供している String クラスです。Java では文字列をクラスとして管理しているため、文字列の本質的な仕組みについては、クラスの理解が必要です。文字列については「7.2 文字列と文字配列」 で詳しく解説することにします。
2.6.3 識別子
ローカル変数宣言文では、型を表すキーワードと変数の名前を設定しなければなりません。Java 言語ではこのような、何らかの実体の認識するための名前を識別子と呼びます。
識別子は、開発者がわかりやすいように自由に設定することが許されていますが、Java 言語が定める命名規則に従わなければなりません。Java 言語では、識別子を Java 文字と Java 数字の並びであると定義しています。
Java 文字とは、ASCII 文字のアルファベット A-Z(\u0041-\u005A)、a-z(\u0061-\u007A) 及び ASCII のアンダーライン _ (\u005F) とドル記号 $ (\u0024) のことを表します。Java 数字とは、ASCII の 0-9 (\u0030-\u0039) までの数字を含む Unicode 文字を表します。
ただし、識別子の先頭1文字は Java 文字でなければならないとされています(つまり、最初の文字に数字は使えない)。さらに、Java 言語が定めるキーワードと同じ名前の識別子を指定することはできません。
Java 言語では ASCII コード以外の、自国語の識別子を使ってもエラーにはなりません。日本語の変数名を宣言することは可能です。しかし、プログラマは他言語との互換性や国際化などを考え、プログラムの中に ASCII コード以外の文字を入れることを習慣的に避けます。また、ドル記号 $ も特別な事情がない限り避けるべきであると考えられています。
識別子の長さは制限されていないので、長い名前でもかまわないのですが、人間が扱うものなので、長くても 20 文字前後が妥当でしょう。
次の識別子はいずれも正しいものです。
- iVariable
- _temp
- VALUE
- kitty_on_your_lap
- i486
- x
- 猫耳原理主義
- $var
逆に、次の識別子はいずれも誤っています。
- 32ivar (先頭が Java 文字ではない)
- class (キーワードである)
これらの条件を守っているのであれば、あとは開発者が変数の目的を表すわかりやすい名前を自由に付けてかまいません。ローカル変数宣言文は次のように行われます。
infloat fvar;
このように変数を宣言することで、あとは変数の識別子を指定するだけでアクセスすることができます。変数の内容を表示したいのであれば System.out.println(iVariable) というように、println() メソッドに変数を渡します。
class Test { public static void main(String args[]) { int iValue; System.out.println(iValue); } }
>javac Test.java Test.java:4: 変数 iValue は初期化されていない可能性があります。 System.out.println(iValue);
コード1をコンパイルしようとするとエラーとなります。これは、iValue 変数を宣言し、記憶領域を確保したものの、その中に何の情報も格納していないためです。変数の目的は情報の保存であり、宣言だけの状態で、何も保存せずに利用するというのは論理的にありえません。そのため、コンパイラはプログラマのミスであると解釈するわけです。
2.6.4 確実な代入
Java 言語では、ローカル変数宣言文で宣言された変数は、その値がアクセスされるまでに必ず値が保持されていなければならないと定められています。これを確実な代入と呼びます。プログラミングの世界では、変数にデータを保存することを代入すると表現します。
コンパイラは変数のアクセスを認識すると、厳密な手順の解析を行って確実な代入状態であるかどうかを調べます。そして、値が保持されていることが保証できない場合、コンパイル・エラーを発生させます。コード1は変数を正しく宣言しているものの、何の値も保存していなかったために、確実な代入状態ではないと判断されたのです。
変数に目的の情報を保存するには、通常は、代入演算という方法を使いますが、これは「2.8 式と演算」で解説することにしましょう。この場では、変数初期化子と呼ばれるローカル変数宣言文の機能を利用して確実な代入を実現します。
ローカル変数宣言文は、コード1の iValue のように識別子だけを設定する以外に、初期値を同時に設定する方法があります。変数の初期値が確定している場合は、変数初期化子を使って値を保持することができます。
型 識別子 = 変数初期化子
変数初期化子には式文を指定することができます。式文についても「2.8 式と演算」で具体的に説明しますが、ようするに計算式や単一の値を指定することができるのです。次の変数宣言では整数型変数を宣言し、数値 10 で初期化しています。
int iValue = 10;
このように変数を宣言すれば、同時に確実な代入状態であることを保証することができます。
class Test { public static void main(String args[]) { int iValue = 10; System.out.print("iValue = "); System.out.println(iValue); double dValue = 3.14; System.out.print("dValue = "); System.out.println(dValue); String str = "Kitty on your lap"; System.out.print("str = "); System.out.println(str); } }
>java Test iValue = 10 dValue = 3.14 str = Kitty on your lap
コード2は問題なくコンパイルすることができます。プログラムは iValue と dValue の2つの数値型変数を宣言し、同時に初期化しています。その後 println() メソッドで変数にアクセスしていますが、今度は確実に代入されているため、コンパイラはエラーを出しません。
このプログラムでは、数値型以外に、文字列を保存するための String 型変数 str も宣言しています。文字列リテラルは String 型として扱われるため、String 型変数に代入することができます。
2.6.5 変数宣言子
もし、int 型変数を3つ用意しなければならない場合、3回に分けてローカル変数宣言文を記述するのは面倒かもしれません。ソースコードの行数も長くなってしまうため、一ヶ所でまとめて宣言できると便利だと思うでしょう。
変数の宣言において、識別子、または識別子と変数初期化子の構成を変数宣言子と呼びます(このとき、型は宣言子に含まれない)。実は、ローカル変数宣言文は複数の変数宣言子を指定することができると定められています。複数の変数宣言子を指定する場合は、宣言子の間を区切り子のカンマ , を使って分けます。すなわち、次のような形になります。
型 変数宣言子 , 変数宣言子 , ...;
識別子だけ、または変数初期化子を含んでいる場合のいずれも変数宣言子なので、次のローカル変数宣言文は問題ありません。
int iValue1 , iValue2 = 10 , iValue3;
このように、初期化する、しないを問わず、同一の型であれば 1 つのローカル変数宣言文で複数の変数を宣言することができるのです。上記の場合 iValue1 と iValue3 は確実な代入状態ではなく、iValue2 だけが確実な代入状態です。
class Test { public static void main(String args[]) { int iValue = 10 , iCount = 100; System.out.println(iValue); System.out.println(iCount); } }
>java Test 10 100
コード3では、2つの整数型変数 iValue と iCount を宣言しています。実行結果を見てわかるように、これらの変数は正しく宣言され、初期化されています。
2.6.6 名前付け規約
Java 言語ではソースの可読性を向上させるため、変数の識別子に対して名前付け規約を定めています。これは、強制されるものではありませんが、言語仕様として記述されているため、すべての Java プログラマが意識するべき重要な問題です。
変数は、意味のある名前を省略した、単語とならない短い小文字の並びであるべきとされます。例えば、ごく一時的な利用に限られた変数であれば temp、値を保持するのであれば val という名前などが考えられます。
原則として1文字の変数は推奨されません。しかし、一時的な利用や汎用的な利用をされる変数であれば、変数型を連想させる文字を採用するように表2のような規約が定められています。
型 | 1文字識別子 |
---|---|
byte | b |
byte 以外の整数型 | i , j , k |
char | c |
float | f |
double | d |
long | l |
String | s |
これは、必ずしも守らなければならないものではありません。しかし、名前付け規約に従ったコードを書く癖をつければ、Java 言語による集団開発の時に、あなたの書いたソースコードは歓迎されることでしょう。