第2回 Javaの変数の本質を知る
中野克平
2002/11/29
|
今回の内容
|
前回は初めてのJavaプログラムとして、画面に「Hello World!」と表示させました。今回はこのプログラムをベースに、前回とは別のことをさせてみましょう。
今回の学習テーマは変数です。一見地味で面白くないテーマのようですが、変数の本質がわからないと、実はJavaの本質もわかりません。そして学習効率も極端に落ちてしまいます。オブジェクト指向言語であるJava特有の型である「クラス型」「参照型」を理解するために、変数の本質に迫りましょう。
さて、以下のリストを見てください。
public class HelloWorld { |
初めてのプログラム言語としてJavaを学習している方には何やら呪文のような英単語が並んでいますが、「System.out.println("Hello World!");」の部分で画面に文字を表示させていることは分かると思います。「Hello World!」の代わりに日本語で「こんにちは世界!」と記述することもできます。
「こんにちは世界!」を表示するプログラムpublic class HelloWorld { |
「Hello World!」や「こんにちは世界!」のように、「"」〜「"」(ダブルクオーテーション)でくくられた部分を「文字列」といいます。どうしてわざわざ「"」〜「"」でくくるのでしょうか? 文字列であることを明示しないとコンパイラが解釈しようとしてしまうからです。例えば「System.out.println("Hello World!");」という、コンパイラにとって意味のある文字列を表示したいとします。このとき、文字列として明示せず、System.out.println(System.out.println("Hello World!"););のようにしてしまうと、コンパイラはプログラマが何を表示させたいのか分からなくなってしまい、エラーになります。「"」〜「"」でくくることで、コンパイラに対して、「ここは文字列なので解釈しなくていいですよ」と伝えているわけです。
もう1つ、「System.out.println("Hello World!");」の最後に付いている「;」にも注目しましょう。Javaでは「; 」(セミコロン)を使って文を区切ります。別のいい方をすると、文を区切るのに改行しなくてもよいし、文の中に改行があってもよいということです。例えば、以下のプログラムは文法的に正しく、きちんとコンパイルできます。
文中に改行のあるプログラム public class HelloWorld { |
文中の改行はプログラムが読みにくくなるので乱用すべきではありません。文が長く、エディタで表示するときに見栄えが悪くなってしまったときにだけ使うとよいでしょう。
「System.out.println(…)」を使うと、文字列だけでなく、数字や式の計算結果も出力できます。
System.out.println(…)で数字や式の計算結果を表示するプログラムpublic class Calculation { |
このプログラムをコンパイルして実行すると、以下のようになります。
C:\DOCUME~1\MYDOCU~1\MYJAVA~1>javac
Calculation.java |
赤字部分が数字や式の計算結果として表示された部分です。「12345」は数字なので文字列のように「"」〜「"」でくくる必要はありません。また、数字と演算子の組み合わせである「3*6+4/2」は式ですので、実行時に計算されて、計算結果が表示されています。
ちなみに、「*」のように計算させるための記号のことを「演算子」といいます。Javaには次のような演算子があります。
| 優先順位 | 演算子 |
| 高 ↑ ↓ 低 |
[] () |
| ++ -- | |
| ! ~ instanceof | |
| * / % | |
| + - | |
| << >> >>> | |
| < > <= == != | |
| & ^ | >= | |
| && || | |
| ?: | |
| = op=(*= /= %= += -= |
「×」が「*」、「÷」が「/」など、キーボードで入力するプログラム言語では、数学で使う演算子とは若干異なります。演算子には優先順位が決まっています。優先順位の概念は数学でもありますよね。小学校高学年の算数で習ったと思います。例えば、式の中に足し算と掛け算があるときは掛け算を先にする、()があるときは、()の中を先に計算する、という規則のことです。Javaには四則演算用以外にも演算子があり、すべての演算子について優先順位が決まっています。
例えば、以下の式について考えてみましょう。
3*6+4/2 |
「+」よりも「*」や「/」の方が優先順位が高いことは演算子の優先順位表から分かります。では、「3*6」と「4/2」はどちらが先に計算されるのでしょうか?
Javaには「左結合」というルールがありますので、優先順位が同じ場合は、左側の式が先に計算されます。従って、上の式は「3*6」「4/2」「18+2」と計算されて、答えは「20」になります。
| Javaの変数 |
Java以外のプログラム言語の経験がある方は、「なんだか当たり前の説明ばかりで飽きちゃったなあ」と思われたかもしれません。今度は「変数」の説明ですので、「すでにほかの言語を学習したことのある方はまた次回にお会いしましょう」となってもおかしくないですね。しかし、ちょっと待ってください。筆者が最初にプログラム言語を学習してから20年以上たちますが、変数について、きちんと説明している学習本に出合ったことがありません(運が悪いのかもしれませんが……)。
先日もある人からJavaについて質問を受けたのですが、彼が悩んでいたことの根本的原因は、変数とデータ型についてきちんと理解していないことにありました。
まずは、Javaで変数を使ったプログラムを書いてみましょう。
変数を使って計算結果を表示するプログラムpublic class CalcWithParams { |
「変数」という概念は数学に由来するものです。上記のプログラムは、「 2x + 3」という式についてxが2のときの値を計算し、その結果「7」をyに代入して表示するものです。プログラム言語の変数は、数学の変数とまったく同じ役割を果たしていますので、義務教育を終えた方ならだれでも理解できることです。ところが、一般的なプログラム言語学習本は、「変数」という概念を、わざわざ難しく説明していると思うのです。
特にどの本というわけではありませんが、変数の説明に出てきがちな図を示します。
![]() |
|
よくある変数の説明
|
私には、変数の説明をするのに、なぜ「箱」が出てきてしまうのかよく分かりません。新しい概念を身に付けるのは大変なことですので、「箱」という「例え話」を使うという発想は分かるのですが、「変数」はプログラム言語特有の概念でしょうか?
義務教育を終えた方ならだれでも理解できるはずのことを、「変数=箱」という例え話がかえって分かりにくくしてしまっているように思えます。コンピュータの中に箱はできません!
もっと悪いことは、箱という例え話を使うことで、プログラマが変数について理解すべき「変数の宣言はメモリを確保する」ことと、「変数へ代入されるデータのサイズが、型によって異なる」ことの2点が抜け落ちてしまいます。そこで、変数の宣言と代入がメモリをどのように使うのかを見てみましょう。
| 変数の宣言 |
Javaでは、変数を使う前に「宣言」をします。Visual Basicの場合は宣言しない変数でも使えますが、Javaでは変数を使う前には必ず宣言しないといけません。
int a; |
「int」は「integer(整数)」の略で、「int a;」という文で、「これから整数型の変数aを使います」という意味になります。では、この文が実行されると、コンピュータの中では何が起きるのでしょうか?
![]() |
|
「int a;」で起きること
|
上の図をコンピュータの中のメモリだと考えてください。「int a;」という文の本当の意味は、コンピュータ内のメモリのうち、4bytes分を確保し、以後ソースコード中で「a」と呼ぶことにするとコンパイラに対して宣言することです。では、なぜ4bytes分なのでしょうか?
Javaで扱うすべてのデータには「型」があります。すでに説明した文字列も実は「String型」のデータです。データの「型」とは、結局のところ「データを格納するのに必要なメモリのサイズ」のことです。「int a;」という文では、変数aをint型と宣言しています。Javaでは、int型は「4bytes分のメモリを使って表す整数」のことだと定義されているので、4bytes分のメモリが確保されるのです。
Javaで使える型とそれぞれのサイズを以下に示します。
| 型名 | サイズ | 値の範囲 | |
| 整数 | byte | 1bytes | -128〜+127 |
| short | 2bytes | -32768〜+32767 | |
| int | 4bytes | -2147483648〜+2147483647 | |
| long | 8bytes | -9223372036854775808〜+9223372036854775807 | |
| 浮動少数 | float | 4bytes | ±3.40282347E+38〜±1.40239846E-45 |
| double | 8bytes | ±1.79769313486231570E+380〜±4.94065645841246544E-324 | |
| 文字 | char | 2bytes | 0〜65535(Unicode表現) |
| 論理 | boolean | (1bytes) | true/false |
それでは、練習問題を兼ねて、いろいろな型の変数を宣言してみましょう。
いろいろな型の変数を宣言するプログラムpublic class DeclareParams { |
変数の宣言はコンピュータの中に箱を作ることではなく、メモリを型のサイズ分確保することです。では、上記のプログラムでは合計何bytes分のメモリが変数用に確保されるでしょうか? 表の順番どおりに変数を宣言していますので、1+2+4+8+4+8+2=29bytes分のメモリが確保されることになります。
| 変数の初期化と代入 |
変数の宣言は、メモリを必要なサイズ分確保することです。ただし、メモリを確保した段階では、メモリにどんな値が書き込まれているか分かりません。そこで、変数から値を読み出す前に、何かの値を書き込んで変数を初期化する必要があります。初期化せずに変数を使おうとするとコンパイラがエラーを出します。
初期化せずに変数を使おうとするプログラム(エラーになる)public class NoInitParam { |
C:\DOCUME~1\MYDOCU~1\MYJAVA~1>javac NoInitParam.javaNoInitParam.java:4: 変数 a は初期化されていない可能性があります。 |
変数を初期化する方法は、読み出す前に何かの値を代入するだけです。
初期化してから変数を使うプログラムpublic class InitParam { |
C:\DOCUME~1\\MYDOCU~1\MYJAVA~1>javac
InitParam.java |
今度はエラーが発生せずにコンパイルして実行できました。「a = 1;」という文で、変数a用に確保されたメモリに値が書き込まれたからです。
![]() |
|
「a = 1;」で起きること
|
「変数=箱」の例え話が事実を正確に表していないもう1つの点は、メモリに書き込まれるのが「1」ではなく、「00000001」という値であることです。なぜ、「00000001」なのでしょうか?
Javaでは、変数だけではなく、数値を含むすべてのデータに型があります。int型の変数aに代入される数値「1」は、同じくint型に扱われますので、メモリに書き込まれるデータは「00000001」になるわけです。では、もし、変数aがbyte型として宣言されていたらどうなるでしょうか?
byte型は1byte分のメモリを使って整数を表す型ですので、同じ「a = 1;」という文でも、書き込まれるデータは「01」という1byte分のデータになります。「変数は箱だ」と理解してしまうと、代入されるデータが変数の型によって異なることが分からなくなってしまいます。
| プリミティブ型以外の「型」 |
Javaの説明のはずが、「メモリをどう使うのか」の話になるなんて「ずいぶん原始的な話だな」と思いましたか? 実は、intやbyteなどの型を総称してプリミティブ型(基本データ型)と呼びます。英語のprimitiveは「原始的」という意味です。これらの型が、CPUで直接メモリの内容を読み書きして計算させるという「プリミティブ」な用途で使われるからです。
プリミティブでない用途では、すでに少しだけ紹介したString型などが使われます。また、何度も出てきた「System.out.println(…);」という文の「System」や「out」もプリミティブでない型の変数です。プリミティブ型ではない型に「クラス型」や「参照型」があります。次回は、この「クラス型」や「参照型」について説明します。だんだんJavaっぽい話になりますのでご期待ください。
いまから始めるJava バックナンバー
- 第1回 Java2 SDKで学習の準備
- 第2回 Javaの変数の本質を知る
- 第3回 クラスを簡単に理解しよう
- 第4回 クラスの継承の本質を知る
- 第5回 メソッドとコンストラクタはなぜ必要?
- 第6回 Javaプログラムの制御構造を理解する
- 第7回 Javaの制御文を使いこなそう
- 第8回 メソッドの挙動を変えるオーバーライド
- 第9回 クラスのメンバに利用制限を付与するアクセス制御
- 第10回 Javaのクラスをグループ化するパッケージ
- 第11回 Javaのクラスの理解を深める
- 第12回 Javaプログラミングにおけるエラー対処
- 第13回 Javaの例外をスマートに記述する
- 最終回 Javaの抽象クラスとインターフェイス
| 「いまから始めるJava」記事一覧 |
ホワイトペーパー(TechTargetジャパン)
- Android NDKでJNIを使用してアプリを高速化するには (2010/3/17)
C/C++やOpenGL ESといったネイティブコードを使うためのNDKとJNIを紹介し、その使い方や注意点を徹底解説します - 調査の難しい「OutOfMemoryError」事例、5選 (2010/3/11)
Java開発者が避けて通れないメモリ不足エラーの基本的な問題切り分け方法と発生につながる事例、対処法を解説 - 究極の問題解析ツール、逆コンパイラJD-Eclipseとは (2010/3/8)
ライブラリ内で例外が発生! そのクラスのソースコードを調べたい!! 自動で逆コンパイルしてくれる無料Eclipseプラグインがあります - いまさら聞けない「Webサービス」の常識 (2010/2/26)
昨今では企業システムでも使われる「Webサービス」の概念やJava標準のJAX-WSを紹介しJBoss WSでサンプルを作成
|
|
スキルアップ/キャリアアップ(JOB@IT)
スポンサーからのお知らせ
- - PR -
| 「いつかは壊れるサーバ」そんな故障に 迅速で安価に手軽に対応する方法とは? New! |
| 「特権ユーザー」の事件を防げ! 万能権限を持つユーザーの管理方法とは? New! |
| 仮想環境の構築とデータ保護の特効薬?! 実績と信頼性の高いパッケージで安心運用 |
| 仮想環境のバックアップもこれまでどおり 「まるごと取ってまるごと戻す」簡単運用 |
| おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |
| その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |
| 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |
| 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |
- - PR -
お勧め求人情報

**先週の人気講座ランキング**
〜CCNA編〜
| ◆ | TomcatやJBossなどAPサーバ環境に関する 情報を集約! “業務”用APサーバ大百科 New! |
| ◆ | 一気に解説! 最新のクラスタストレージ 「RAIDを超えたストレージ基準」……など New! |
| ◆ | クラウド的ユーザー体験の変化は脅威か? 仮想化技術を使いこなす運用管理術を紹介 New! |

| ◆ | 上司や部下、部署内メンバーとの情報共有 を“ガラッ”と変えるコラボツールとは? New! |
| ◆ | おばかアプリ選手権、第4弾開催中!! ムダにカッコよくてくだらない作品求ム! |
| ◆ | 社内ファイルサーバを“クラウド”に統合 VPN直結「クラウド型ストレージ」を紹介 |

| ◆ | Twitterのアカウントはなぜ突破された? メールによる新手の攻撃手法とその対策 |
| ◆ | もう仮想化のお試しフェイズは終わりだ! Hyper-V 2.0が基幹システムも仮想化 |
| ◆ | 美人!? まあまあ? 気になる いやし系!! PV急増で「美人時計」がとった手段とは? |

| ◆ | クライアント企業から求められる人材 ⇒IT技術と経営戦略を併せ持つ「戦略家」 |
| ◆ | .NET編集長が実践する「技術情報検索術」 サンプル・コードを簡単に探す“技”は? |
| ◆ | 業務効率と情報セキュリティ対策を両立! 手間なく確実に機密情報を守る方法とは? |

| ◆ | 進化を続ける富士通ストレージETERNUS DX 製品開発者の自信を裏付けるものとは何か |
| ◆ | 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |

| ◆ | 【CTC事例】約30の基幹システムを統合! 膨大なバッジジョブを制御した方法は? |
| ◆ | 仮想化すればコストは削減できるか? 仮想化に必要な「3つの視点」を解説する |
| ◆ | その数、なんと400台以上! グループ内 サーバの「統合管理」によるメリットは? |









