これからJava言語によるプログラミングを学びます.
コンピュータのプログラムを作ってそれを実行する流れについてご存知でしょうか?
それをご存知の人は,この「導入」を読み飛ばしてページをスクロールしてください.
「プログラム」(program)は直訳しますと,「予定」「計画」「番組」…を意味します.
つまり,すべきことを順番に書き綴った手順書のようなもので,コンピュータが実際に情報処理を
遂行する動作もプログラムという形で記述されています.
コンピュータで利用する各種のアプリケーションソフトウェアもその正体は「プログラム」で,
アプリの内部にはその動作や振る舞いの流れが手順として記述された「プログラム」が
びっしり詰まっています.
つまりこれから何を学ぶかというと,情報処理の手順をJavaという言語で書き綴る方法です.
そして,ひと通りのことを学ぶと自分自身でコンピュータ用のアプリが作れるようになります.
次に,コンピュータは本当はどんな装置が理解していますか?
簡単にいうと,
● 入力装置から情報(数値)を読み取って記憶装置にそれを書き込む
● 記憶装置に書き込まれている内容(数値)を操作する
● 記憶装置に書き込まれている内容(数値)を出力装置に送る
くらいのことをやるだけの装置です.
ですから「言語で動作を記述する」といっても,上のようなことをやるための手順を
書き並べるだけです.
しかも扱う「情報」「データ」といっても結局は数値でしかなく,プログラム言語で書くことも
● 記憶装置に数値を書き込む
● 記憶装置に書き込まれている数値を使って計算を行う
● 計算結果を記憶装置に書き込む
● 各種装置(入力装置や出力装置)と記憶装置の間で数値を受けたり送ったりする
みたいな単純なことばかりです.
このように,意外なくらい単純なことでコンピュータのアプリはでき上がっているわけです.
プログラミングを学ぶということは,このようなことを具体的に学ぶことです.
まずはJava言語の文法と作法を学びましょう.
最初に「クラス」「mainプログラム」というものを学びます.
Javaではプログラムを「クラス」という概念の実体として扱います.
この「クラス」というものについては「オブジェクト指向」のページで詳しく説明しますので,
今はまだこだわらないでください.
そしてプログラムを作るときは,必ずそれに名前をつけます.
要約しますと,Javaでプログラムを作る行為は
「クラスの実体を1つ新たに名前をつけて作る」
ことです.そして,そのプログラム(アプリ)を起動すると,そのアプリの中に登録された
「mainプログラム」の実行を開始するというわけです.
ここまでのことを実感していただくために,JCPadを紹介するページで示したサンプルプログラムを
ここでもう一度見てみましょう.
プログラムの1行目に "class Sample0" という記述がありますが,これは
「ここに"Sample0"という名前のクラスを作る」
という宣言(定義)をしていることになります.
このようにプログラムを書くことで,"記述内容" の内容を持つ "クラス名" という
クラスができあがります.そして "記述内容" の中に実際の動作を書き綴った
「mainプログラム」(2〜4行目)を含めるわけです.
ところでプログラム中によく現れる括弧の表現 "{ 〜 }" ですが,この括弧がとても重要です.
この括弧のくくりは,何かの記述の範囲を明確に示すもので,入れ子の形をとることができます.
この「入れ子」というのも慣れないうちはわかりにくいかもしれませんが,日本語の運用方法に喩えますと
「セリフの中にセリフがある」構造といえばわかるでしょうか.(下の例)
日本語での例
"わたしは彼が「俺が彼女に『君が好きだ』と言ったら笑われた」というのを聞いた."
日本語の場合は,多重の入れ子の構造を作る場合は分かりやすさのために "「」" と "『』" を
区別しますが,プログラム言語の場合は同じ括弧を使うわけです.
(今後くれぐれも注意してください)
次は「mainプログラム」の書き方です.
この "処理の手順" のところに,本当の意味でのプログラム(やることの手順)を記述するわけです.
"public" "static" "void" "main" "String" "argv" がそれぞれ意味することは今後順をおって説明
していきます.
※ Javaは言語としての完成度が高いので,初歩の段階からいきなり高度な概念の内容が出てきます.
初心者の人にとってはもどかしい感じがすると思いますが,説明が後回しになることが多々あることを
予めご理解ください.後で必ず理解できますから安心してください.
さて,"処理の手順" には「手順」を書くので,複数の「命令文」を書き並べることができます.
上の Sample0.java の例では実行している命令文は
System.out.println("Hello, Java.");
の1つだけですが,ここでこの文の説明をしておきます.
この文は
● System (コンピュータ)の
● out (出力画面)に対して
● println("Hello, Java.") を実行する
と解釈します.このようにドット "." の表記で「何に対して何をするのか」がはっきりとわかります.(下図)
命令文の1つ1つの終わりには必ず終端の記号であるセミコロン ";" を書きます.
(日本語でいうところの「。」英語でいうところの「ピリオド」に相当します)
プログラムには当然ですが複数の文を書き連ねることができます.
次のサンプルプログラム "Sample0_1.java" をコンパイルして実行してみてください.
コンパイルして実行すると次のような表示になります.
Hello, Java.
My name is John Smith.
How do you do?
3つの文が記述された順番に実行されたことがわかります.
コンピュータは記憶装置き書き込まれた数値を処理するものですが,
実際には数値はどのように記憶装置に書き込まれるのでしょうか.
主記憶装置は1バイト(8ビット)単位にビットのデータを記録する装置ですが,
Javaをはじめとするプログラム言語では,「変数」という考え方に基いてデータを
記憶装置に格納することができます.
「変数」というのは喩えていうと「数値の容れ物」です.
実際に変数を用意するための宣言文というのがあり,それを記述することで,
変数(値の容れ物)を用意することができます.
次のプログラム "Sample1.java" を見てください.
このプログラムの3行目に "int" という記述がありますが,これが整数の変数を宣言して
整数の値の容れ物を確保するためのものです.
何をするプログラムかはだいたいおわかりいただけるかと思いますが,
a, b, c という3つの整数を格納する変数(容れ物)を用意して,
aに2を,bに3を格納した後,この2つの内容を加算し,その結果をcに格納して
最終的にcの内容を画面に印字出力しています.
フプログラミングの初心者の人には少しわかりにくいかもしれませんが,
3〜6行目の動作を下のイラストに示しますので,プログラムと合わせて理解してください.
● 3行目の記述 | |
● 4行目の動作 (aに2を入れる) | |
● 5行目の動作 (bに3を入れる) | |
● 6行目の動作 (aの値とbの値を足した ものをcに入れる) | |
最終的な状態 |
"Sample1.java" をコンパイルして実行すると計算結果(cの内容)である5が表示されます.
ところで整数とは小数点以下のない数値ですが,
小数点つきの数を扱うにはどうすればよいのでしょうか.
次のプログラム "Sample1_1.java" をコンパイルして実行してみましょう.
このプログラムの6行目に "a / b" という記述がありますが,これは "a÷b" の計算を意味します.
この行を実行すると変数cにはどんな値が入っているでしょうか?
"2÷3" を実行するわけですから,cに格納される値は 0.666… になるように思われますが,
実行してみると 0 が表示されます.なぜでしょうか?
理由は,使用している変数が "整数" のタイプだからです.
整数型の変数には文字通り「整数」しか格納することができず,
小数点以下の部分は切り捨てられてしまいます.これが原因でした.
もちろんJavaには小数点つきの数(浮動小数点数)を扱うこともできます.
上のプログラム浮動小数点数を扱う形に改造した "Sample1_2.java" を次に示します.
これをコンパイルして実行してみましょう.
結果(cの内容)が小数点つきで表示されることがわかります.
このプログラムの3行目に "double" とあります.この形で宣言された変数は
浮動小数点数を格納します.
※ 本来,浮動小数点数は "floating point number" のことで,変数の型としても "float" というものが
用意されています.ただ float 型の変数は表現できる小数点以下の桁数が短くて実用性が低いので,
実際には float の倍の精度で値を保持できる double の型として変数を宣言することが一般的です.
(double:「倍精度」"double precision" の略)
Javaの変数には様々な「型」があり,整数,浮動小数点数,文字列といった種類の違うデータのために
それぞれ違う型の変数を使い分けます.
(文字列オブジェクト)
Javaで文字列(記号列)のデータを格納するには "String" 型のオブジェクトを宣言します.
※ 厳密にいうと String は変数ではなく「オブジェクト」です.これに関してはまた.
次のプログラム "Sample1_3.java" を実行するとどのような表示になるか想像してみてください.
コンパイルして実行してみると意外な結果になることがわかります.
"12+34" と考えて,"46" と表示される結果を予想してしまいがちですが,
今回の変数(オブジェクト)a,b,c は「文字列」です.(数値ではないわけです)
試しに,4行目と5行目を
a = "Personal";
b = "Computer";
と書き換えて実行するとどうなるか試してみてください.
「オブジェクト」について少し説明:
そろそろ「オブジェクト」という言葉がたくさん出てくるようになります.詳しくは「オブジェクト指向」
のところで説明しますが,それまで全く説明がないとやはり釈然としませんので,少しだけ説明しておきます.
実際に記憶装置の上で情報を保持するための仕組みとして「変数」というものを学びました.
数値などの値を1つ保持するには変数を用意するだけで十分なのですが,
たとえば「たくさんの値をまとめて保持しておきたい」といった場合は,変数を使用するだけでは
不便です.(たくさん変数を宣言するのも大変面倒なことになります)
そこで,変数よりももっと高度な記憶管理の仕組みが求められます.
たとえば表計算ソフトのスプレッドシートのように,たくさんの値をまとめて保持する「配列」という
記憶管理の仕組みもあります.
もちろん「配列」はオブジェクトの1つの形態で,実際にはプログラムを作成する人が
都合に応じて色々な記憶構造を設計して情報の管理に利用することができます.
これだけの説明では,まだ「オブジェクト」の意味がはっきりイメージできないと思いますが,
「複雑な記憶を保持するための構造物を設計して,それを記憶装置の上に実現したもの」
ということで今は理解しておいてください.くわしくはまた.
変数の内容を表示するために,これまで "System.out.println(〜)" という文を使ってきましたが,
"System.out" に対する出力の方法は他にもあります.
次の2つのプログラムを見比べてください.
違いがわかりますか?
よく見ると,"println" と "print" の違いがあることがわかります.
どちらも "System.out" に対する出力を行うものですが,実行してみるとその違いがはっきりとわかります.
(両方ともそれぞれコンパイルして実行してみてください)
"println" は印字出力は行単位で行われ,これを実行するたびに改行されてゆくのがわかりますが,
"print" の方は改行が行われず,立て続けに(横に続いて)印字されることがわかります.
次はまた印字出力に関する別の方法「書式つき出力」です.
「どんな体裁で印字するか」を細かく指定できる出力の方法です.
数を何桁で表示するか,小数点以下は何桁印字するか,といった体裁です.
次のサンプルプログラム "Stdout1_2.java" を見てみましょう.
このプログラムの中では,a,pi,sの3つの変数に値がセットされています.それらを "printf" という
メソッドを用いて印字しています.
※ 「メソッド」という用語ですが,詳しくはオブジェクト指向を解説するところで説明します.
まずは,このプログラムをコンパイル・実行して,これら3つの値がどのように印字されるかを確認して下さい.
印字出力は少々味気ない感じですが,下の図のように長さを指定した形で印字されていることがわかります.
実際にデータをディスプレイや紙に印字する場合は,位置と長さを調節した形で印字しますが,
そのような場合にこの "printf" を用いるわけです.
次はキーボードからの入力について説明します.
例として,キーボードから文字を1つ受け取って,それをそのまま画面に表示するプログラムについて考えます.
次のプログラム "Stdin1.java" を見てください.
このプログラムは,整数の変数cを用意し,キーボードから1文字読み取った後,その文字のコードをcに
格納するものです.4行目にある "System.in" がコマンド画面であり,そこから "read" というメソッドで
文字を1文字読取ります.
このプログラムをコンパイルした後,実行すると次のようになることを確認して下さい.
(1) | ← 実行開始 | |
(2) | ← キーボードの "a" をタイプして, | |
(3) | ← Enterを押したところ "a"の文字コードである 97が表示されている. |
一応,これで「押されたボタンの文字コード」を取得することができることがわかりました.
しかし,現実的な局面では文字コードを直接取得するだけでなく,"1"と入力されれば整数の1を,
"34.5"と入力されれば実数の34.5を変数に与えたいことも多いはずです.
そういう場合に対応する方法ももちろんあります.
次のサンプルプログラム "Stdin1_int.java" は,入力された文字の意味する通りの整数値を
変数に格納する例です.
6行目に "Scanner" というクラスが出てきました.それと "new" という言葉も出てきました.
これもくわしくは「オブジェクト指向」のところで説明しますが,ここでは,
「オブジェクトを新たに主記憶の上に確保する」
ための命令だと思ってください.
"System.in" はコマンド画面の入力のことですが,ここから得られた(キーボードから入力された)情報を
保持する "Scanner" という種類のオブジェクト "si" を主記憶上に作る処理を行っています.
この "new" の実行の後は,キーボードから入力された情報が "si" の中に格納されていると
考えてください.
この後,7行目,8行目にある "nextInt" が実行される度にキーボードからの入力を取りにゆきます.
このプログラムをコンパイルしたあと実行している様子を下に示します.
(1) | 実行開始 この段階ではプログラムの7行目の nextInt命令を実行して入力を 待っている. | |
(2) | aへの入力待ち "3"を押してEnterを押したところ. nextInt命令を実行し終わり, 変数aに3が格納された. 更に8行目のnextInt命令を 実行して入力を待っている. | |
(3) | bへの入力待ち "4"を押してEnterを押したところ. nextInt命令を実行し終わり, 変数bに4が格納された. 更に9行目以降が実行され 計算結果が表示されている. |
参考: 浮動小数点数を読み取る "nextDouble" という命令(メソッド)もあります.
コマンド引数について:
さて,メインプログラム "main" を書き始める行にある "String argv[ ]" について説明します.
"String" で始まるので文字列型オブジェクトであることは推察できるのですが,その後の "argv[ ]" が
まだ謎です.
毎回まるでおまじないのように書いてきたこの部分ですが,ここで少し明らかになります.
コンピュータのプログラムはコマンド画面から起動することができますが,その際にプログラムに情報を
与えることができます.(起動時の情報付与)
次のプログラム "Argtest1.java" を見てください.
コマンド操作でプログラムを起動する場合,プログラム名の後ろにスペースで区切って複数の情報を
与えることが出来ます.実際にこのプログラムをコンパイルした後,実行した例を下に示します.
起動時に,プログラム名である "Argtest" の後ろに "a b c d" という4つの記号をつけています.
このような,コマンド起動時の付加情報を「コマンド引数」といいます.
コマンド引数を受け取って記憶に格納するしくみが,mainの後ろの argv[ ] です.
このプログラムの4行目と5行目に argv[0], argv[1] から値を取り出している部分がありますが,
このように,
argv[0] 最初の引数,
argv[1] 2番目の引数,
argv[2] 3番目の引数,
:
と順番に格納されます.
argvはStringの型で宣言されていることからわかりますが,文字列型のオブジェクトです.
ですから当然,数値情報などをコマンド引数として与えても,それらは「数値」の情報ではなく,
記号列としての情報です.
記号列(文字列)の情報として与えた情報を,「数値」として解釈して,int型の変数やdouble型の変数に
格納したい場合はどうすればいいでしょうか.
次のプログラム "Argplus.java" を見てください.
このプログラムはコマンド引数として与えられた数値の足し算をするものです.コンパイルして実行した
例を下に示します.
コマンド起動時に,プログラム名であるArgplusの後ろに2と3を与えています.
これらはargvに受け取られますが,その段階ではまだ文字列(ただの記号列)です.
文字列のデータを数値として解釈(変換)するための処理が4行目と5行目にある "Double.parseDouble" です.
これの実行の結果,double型の数値の情報として変数a,bに値が格納されています.
ただ,先頭が "Double.〜" ではじまる文もちょっと釈然としない感じがしますが,ここでは
「浮動小数点に関する処理を意味する計算命令」と解釈しておいてください.今後も "Double.〜" ではじまる
別の計算を扱うことがあります.
(厳密には「クラスメソッド」というのですが,これに関しても「オブジェクト指向」のところで
説明します)
クラスメソッドとして重要なものに数学的関数の計算をするものがあり,そのよう文は "Math.〜" で
はじまります.一応1つ例を示します.次のプログラム "Sqrttest.java" を見てください.
これは与えられた数の平方根を求めるプロムラムです.変数aに入っている値の平方根を求め,それを
変数bに格納した後,画面に印字出力します.
5行目にある "Math.sqrt" が平方根を求めるものです.
このプログラムをコンパイルして実行してみてください.(下の実行例を参照)
(実はわざとエラーを起こすようにしています)
計算結果として "NaN" が表示されています.さて,この実行例は何を意味するのでしょうか.
プログラムの4行目を見ると,aに-2.0が与えられています.つまり負(マイナス)の数の平方根を
求めようとしたわけです."Math.sqrt" は正の数の平方根しか求めることができず,エラーとなった
わけです.
では,4行目のマイナス記号 "-" を削除して,aに2.0を与える形にして再度コンパイルと実行を
してみてください.下の実行例のようになると思います.
コンピュータのプログラムは,書き綴った命令文をその順番どおりに1つづつ実行するものというのは
もう十分に理解できると思います.
しかし実用的なプログラムを作成するためには,いろいろと条件を判定しながらプログラムの流れを適宜変更する
必要がでてきます.
例えば「〜の条件を満たす場合は〜を実行し,そうでない場合は別の〜を実行する」とか,
「〜の処理を複数回繰り返す」といった形でプログラムの実行の流れを制御することで高度な情報処理が
実現できるわけです.
ここでは,プログラムの流れを切り替えたり,特定の部分を繰り返したりする「制御構造」について説明します.
与えられた条件にしたがって処理を切り替える方法です.
if文の応用例として次のプログラム "Cond1.java" を見てください.
このプログラムの4行目で,コマンド引数から数値を1つ取得して変数aに格納しています.
5行目の "if" 文でaの値が正(positive)かそうでないかを判定して,判定結果を表示します.
このプログラムをコンパイルした後,実行した例を下に示します.
上は実行時に3を与えた場合,0を与えた場合,-2を与えた場合の例です.
複数の条件を与え,その中から成立した条件に対応する処理のみを実行することも可能です.
次のプログラム "Cond2.java" を見てください.
これは先のプログラム "Cond1.java" を改良したもので,正(positive),ゼロ,負(negative)の
どれになるかを判定する形にしたものです.
このプログラムをコンパイルした後,実行した例を下に示します.
(条件文について)
if文の条件判定に用いる条件文について下記にまとめます.条件式の記述 | 意味 |
値1 == 値2 | 値1と値2が等しい |
値1 != 値2 | 値1と値2が等しくない |
値1 < 値2 | 値1より値2が大きい |
値1 > 値2 | 値2より値1が大きい |
値1 <= 値2 | 値2は値1以上である |
値1 >= 値2 | 値1は値2以上である |
結合 | 意味 |
条件1 && 条件2 | 条件1 かつ 条件2 |
条件1 || 条件2 | 条件1 または 条件2 |
(条件文が持つ値について)
「条件文は値を持ちます」(?)
ちょっと不思議な感じがする説明ですね.下のプログラム "BooleanTest1.java" を見てください.
4行目がちょっと不思議な感じですね.「5は3より大きい」という文が変数bに代入されています.
コンパイルして実行してみてください.
"True" と表示されますね.
じつは条件文というのは「値」を持っています.どんな値かといいますと,
"True" か "False" の2種類の「論理型」(boolean)の値です.つまり真か偽です.
条件が成立する場合は全体として "True"(真)を,成立しなければ "False"(偽)という値になります.
上の例は,これを明に示すものです.
「1から100までの数の合計を求める」プログラムについて考えましょう.どのように書けばよいでしょうか.
変数を1つ(例えば int 型の n を)用意して,
n = 1 + 2 + … + 100;
とやっても答えは出ますが,これではちょっと面倒ですね.
同じような作業を繰り返し実行する場合に便利な書き方があります.
次のプログラム "Addall1.java" を見てください.
6行目の "while" という文は繰り返しの処理を実行するものです.この文の記述方法を下に示します.
"Addall1.java" の動作を噛み砕いて説明すると,次のようになります.
1) 計算結果を格納する変数 n に 0 を入れて初期化する.
2) n に c の値を累積する.(c には最初は1が入っている)
3) c の値を 1 増やす.
2〜3の処理をcが100以下の間繰り返す.
繰り返しの処理を行うために必要なことを整理すると次のようなポイントがあります.
● 繰り返し処理を始める前の準備をする(初期化)
● 実行する条件を与える(条件文)
● 1回の処理を終った後の処理を実行する(後処理)
上のプログラムでは,cに1をセットする処理が「初期化」,"c<=100" という文が「条件文」,
"c = c + 1" という処理が「後処理」に相当します.
「初期化」「条件文」「後処理」をわかりやすく指定して,もう少し簡潔に記述する方法があります.
次のプログラム "Addall2.java" を見てください.
これは "for" (下記)を使った繰り返し処理の例です.
これを踏まえて "Addall2.java" を解釈すると次のようになります.
このプログラムにおける後処理に "c++" という記述がありますが,これは「cの値を1増やす」処理です.
すなわち,"c = c + 1" と同じです.この「++」をインクリメント演算子と呼びます.
同様に,変数の値を1つ減らすデクリメント演算子もあり「--」と書きます.