Javaプログラミングの基本
今週は、コンピュータにいろいろなことをさせるために必要な、Javaプログラミングの基本を学びましょう。
先週のプログラムは、ただ「Hello, world!」と出力するだけでした。ですが、本連載でプログラミングを学び、きちんとプログラムを書けるようになれば、コンピュータを使って難しい問題を解決したり、あなたの仕事を自動的に片付けさせることもできるようになります。
#通常のプログラミング入門書では、int型、変数、演算子、条件分岐などを一通り説明して、つまりC言語と同じ部分を一通り説明して、それからクラスの説明に入ることが多いと思いますが、ここでは敢えて、オブジェクトを使う方が基本で、プリミティブ型はおまけ、という流れにしました。
オブジェクト
オブジェクト指向言語であるJavaでは、必要なオブジェクトを作り、それらに名前をつけて、1つずつ操作していく、という考え方が、プログラミングの基本です。
オブジェクトと変数
Javaでは、オブジェクトの雛形である「クラス」から、「new」というキーワードを使って、オブジェクトを作ります。作られたオブジェクトを「インスタンス」と呼びます。
例えば、ClassXというクラスのインスタンスを作るプログラムは、以下のようになります。
new ClassX();
1つのクラスから、いくつものインスタンスを作れます。インスタンスを区別したり、作ったインスタンスを操作するために、通常はインスタンスに名前を付けます。それを「変数」と呼びます。
インスタンスに名前を付ける時は、等号(イコール)を使います。以下のプログラムは、ClassXというクラスのインスタンスを1つ作り、それにobjectXという名前を付けた例です。
ClassX objectX = new ClassX();
先頭の「ClassX」は、変数の型を表しています。ここでは、objectXという名前の変数は、ClassXというクラスのインスタンスを示すものである、と宣言をしています。Javaで変数を使う時は、必ず、型を指定しなくてはなりません。
#このことを、Javaは静的型付け言語である、と言います。C言語やC#なども同様です。一方、Perlなどのスクリプト言語では、型を指定しなくても自由に変数を使えるものがあります。これを動的型付け言語と言います。
1つのインスタンスに、いくつもの名前を付けることができます。以下のプログラムは、ClassXというクラスのインスタンスに、aとbという2つの名前を付けた例です。aとbはただの別名であり、同じインスタンスを示しています。
ClassX a = new ClassX(); ClassX b = a;
さて、ここでは例として、貯金箱にお金を貯めていき、最後にいくら貯まったかを出力するプログラムを書いてみましょう。
まずは、プログラムのイメージを、頭に思い浮かべてみましょう。貯金箱が1つ、そして、手元には500円玉が4枚あります。この4枚の500円玉を、1枚ずつ貯金箱に入れていきます。
#ここで図がほしい。
プログラムの第一歩として、まず、この図に登場するオブジェクトを作ります。
そのためには、「貯金箱」や「500円玉」の雛形、つまり、クラスが必要です。しかし、これらのクラスを自力で作るのは、もう少し学習を進めてからにしましょう。
幸い、Javaのコアライブラリには、プログラミングに役立つ便利なクラスが豊富に用意されています。ここでは、「貯金箱」の代わりに、Javaが提供するArrayListクラスを使うことにしましょう。また、「500円玉」の代わりに、Objectクラスを使うことにします。
貯金箱のオブジェクトを1つ、500円玉のオブジェクトを4つ作るプログラムは、以下のようになります。
import java.util.ArrayList; class MyFirstProgram { public static void main(String[] args) { ArrayList savings_box = new ArrayList(); Object coin500_a = new Object(); Object coin500_b = new Object(); Object coin500_c = new Object(); Object coin500_d = new Object(); } }
これは、先週のHello worldプログラムをコピーして、「Hello, world!」と出力していた箇所を書き換えたものです。貯金箱にはsavings_boxという名前を、4枚の500円玉にはcoin500_a〜coin500_dという名前を付けています。
なお、冒頭の「import java.util.ArrayList;」は、ArrayListクラスを使うための、おまじないだと思ってください。
このプログラムを実行すると、5つのオブジェクトが作られます。とはいえ、コンピュータの中で作られるだけなので、ここではまだ、画面には何も表示されません。
オブジェクトの操作
オブジェクトを作ったら、次はそのオブジェクトを操作します。オブジェクトを操作するには、オブジェクトに対してメッセージを送ります。Javaでは、オブジェクトにメッセージを送ることを、「メソッドを呼び出す」と言います。
メソッドを呼び出す時は、ピリオドを使います。以下のプログラムは、objectXという名前のインスタンスに対して、メソッドを呼び出した例です。
objectX.doSomething();
「doSomething」というのが、メソッドの名前です。どのようなメソッドを呼び出すことができるのか、そして、メソッドを呼び出すと何が起こるのかは、クラスで定義されています。定義されていないメソッドを勝手に呼び出すことはできません。
メソッドを呼び出す際に、一緒に他のオブジェクトを渡すこともできます。これを「引数」と呼びます。引数は、括弧の中に書きます。以下のプログラムは、objectXという名前のインスタンスに対して、abcという名前のオブジェクトを渡した例です。
objectX.useAbc(abc);
引数に何を渡せるのか、そして、渡した引数を使って何が起こるのかは、クラスで定義されています。定義されていない引数を勝手に渡すことはできません。
では、さきほどの貯金箱のプログラムの続きを書いてみましょう。
さきほどは、貯金箱のオブジェクトを1つ、500円玉のオブジェクトを4つ作りました。次に、4枚の500円玉を、1枚ずつ、貯金箱に入れてみます。
貯金箱であるArrayListクラスには、オブジェクトを1つずつ入れるためのaddメソッドが用意されています。addメソッドに、貯金箱に入れる500円玉のインスタンスを、引数として渡します。
import java.util.ArrayList; class MyFirstProgram { public static void main(String[] args) { ArrayList savings_box = new ArrayList(); Object coin500_a = new Object(); Object coin500_b = new Object(); Object coin500_c = new Object(); Object coin500_d = new Object(); savings_box.add(coin500_a); savings_box.add(coin500_b); savings_box.add(coin500_c); savings_box.add(coin500_d); } }
このプログラムを実行すると、貯金箱に500円玉が4枚入ります。とはいえ、コンピュータの中で作られた貯金箱に入るだけなので、ここではまだ、画面には何も表示されません。
値
Javaでプログラムを書くには、オブジェクトだけでなく、数値や文字といった基本的な値も使います。これらの値をプリミティブ型と呼びます。
値の使い方は、C言語など多くのプログラミング言語でも共通ですので、こちらも良く理解してください。
リテラルと演算
値の使い方は、オブジェクトの使い方とはだいぶ違っています。
まず、値はオブジェクトではないので、「new」を使って作ることはしません。「1」とか「1.234」などの値を、プログラムにそのまま書きます。これを「リテラル」と呼びます。
また、値はオブジェクトと違って、メソッドを呼び出すことはできません。その代わり、「+」や「-」などの演算子を使って、計算をすることができます。
以下のプログラムは、数値の計算をした例です。掛け算が「*」、割り算が「/」の記号になっていますが、基本的にふつうの算数と同じ書き方ですので、分かりやすいと思います。掛け算・割り算が、足し算・引き算より優先することも算数と同じです。括弧を使って、計算の順序を変えることもできます。
1+2 2*3 (1+2)/3-(4+5)*6
変数と演算
オブジェクトと同じく、値でも変数を使えます。ただ、オブジェクトと値とでは、変数の意味が少し違います。
オブジェクトの場合は、オブジェクトに名前を付けたものが変数でしたが、値の場合は、値を格納するための入れ物、と考えてください。
値を変数に格納する時も、等号(イコール)を使います。以下のプログラムは、1と2を足した結果を、aという名前の入れ物に格納した例です。
int a = 1 + 2;
#算数では、等号(イコール)は左右が等しい、という意味ですが、Javaのプログラムでは、右側の計算結果を左側の入れ物に格納する、という意味になります。
先頭の「int」は、変数の型を表しています。ここでは、aという名前の、整数を格納するための入れ物を作り、そこに1足す2の結果を格納しています。
値を格納した変数に対して、さらに演算をすることもできます。以下のプログラムは、3という値を変数aに格納した後、さらに1増やし、さらに5を足した例です。
int a = 3; a++; a += 5;
「++」という演算子で、値を1増やすことができます。また、「+=」という演算子で、値をさらに加算することができます。
ところで、オブジェクトの場合の、1つのインスタンスに、別名を付けることができました。例えば、以下のプログラムでは、aとbはただの別名であり、同じインスタンスを示しています。
ClassX a = new ClassX(); ClassX b = a;
しかし、値の場合は、別名を付けることはできません。例えば、以下のプログラムでは、aとbは別の入れ物です。aの値は4になりますが、bの値は元通り、3のまま残っています。
int a = 1 + 2; int b = a; a++;
では、さきほどの貯金箱のプログラムの続きを書いてみましょう。
貯金箱に入っている500円玉の枚数を調べて、500円を掛けて、貯まった金額を計算してみましょう。
貯金箱であるArrayListクラスには、入っているオブジェクトの数を調べるsizeメソッドが用意されています。sizeメソッドを呼び出すと、入っているオブジェクトの数が、戻り値として返されます。
import java.util.ArrayList; class MyFirstProgram { public static void main(String[] args) { ArrayList savings_box = new ArrayList(); Object coin500_a = new Object(); Object coin500_b = new Object(); Object coin500_c = new Object(); Object coin500_d = new Object(); savings_box.add(coin500_a); savings_box.add(coin500_b); savings_box.add(coin500_c); savings_box.add(coin500_d); int num_of_coins = savings_box.size(); int total_yen = num_of_coins * 500; System.out.println(total_yen); } }
Hello worldプログラムと同じく、「System.out.println」を使って、貯まった金額を出力しています。このプログラムを実行すると、「2000」と出力されます。
文字と文字列
Javaのプログラミングでは、文字や文字列も良く使います。
文字列という用語は聞き慣れないかもしれません。文字列とは、文字をいくつか繋げたものです。「A」や「あ」などが文字、「ABC」や「あいうえお」が文字列です。
文字
Javaの文字は、プリミティブ型の1つです。ですので、数値と同じく、プログラムにそのまま文字を書けます。文字のリテラルは、クォーテーションマークで囲みます。変数の型は、charです。
char a = 'A'; char b = 'あ';
文字に対しても、「+」や「-」などの演算子を使って、計算をすることができます。
ただし、以下のプログラムを実行しても、「ABC」とはなりません。
char a = 'A'; char b = 'B'; char c = 'C'; System.out.println(a + b + c);
Javaの文字は、実は、UNICODEと呼ばれる整数です。「A」や「あ」などの文字のそれぞれに、異なる番号が割り振られています。文字の足し算は、その番号の足し算となるだけで、文字を繋げることにはなりません。
文字列
Javaの文字列は、ちょっと特殊です。
文字とは違って、Javaの文字列は、オブジェクトの一種です。しかし、ただのオブジェクトではありません。オブジェクトでありながら、プリミティブ型と同じように扱えるような工夫もされています。
文字列はオブジェクトですので、キーワード「new」を使って、インスタンスを作ることができます。雛形となるクラスは「String」です。しかし、プリミティブ型のように、プログラムにそのまま文字列を書くこともできます。文字列のリテラルは、ダブルクォーテーションマークで囲みます。
String a = new String(); String b = "ABC";
文字列はオブジェクトですので、メソッドを呼び出すことができます。しかし、プリミティブ型のように、「+」演算子を使うこともできます。以下のプログラムは、どちらも、「ABC」と「DEF」を繋げて、「ABCDEF」という文字列を作っています。
String a = "ABC"; String b = "DEF"; String c = a.concat(b); String a = "ABC"; String b = "DEF"; String c = a + b;
さきほど、オブジェクトとプリミティブ型とでは、変数の意味が違う、と言いました。文字列はオブジェクトですが、変数の意味は、むしろ、プリミティブ型に似ています。
例えば、以下のプログラムでは、aは「ABCZZZ」となりますが、bは「ABC」のまま残っています。
String a = "ABC"; String b = a; a += "ZZZ";
#注意!
ここの説明は誤解を招くかもしれません。
bにaを代入した時点では、ふつうのオブジェクトと同様、bはaの別名になっています。
その後の「a += "ZZZ";」は、aの示すインスタンスに「ZZZ」を加えている訳ではなく、「AAA」と「ZZZ」を繋げた新しいインスタンスを作って、それをaに代入しているだけです。つまり、aという名前を、別のインスタンスに付け替えているだけです。ですから、bがaの別名だとしても、aとbが違った文字列になるのは当然です。
そう考えると、「+=」演算子は、ただ「a = a + ○○」を簡略化しただけ、と言った方が良いかもしれません。
実は、プリミティブ型の「+=」演算子の説明もそれで通せば、「オブジェクトの変数は名前で、プリミティブ型の変数は入れ物である」という区別も不要になります。ただ、そう言ってしまうと、今後はプリミティブ型の説明がちょっと実態と違ってしまいます。
処理の流れ
※以下、TBD。条件分岐や反復など。
※プリミティブ型とオブジェクトの同一性(==)の違いについても。なお、文字列はequals()で判定する。
はじめてのJavaプログラム
今週はいよいよJavaプログラムの作成から,それを実際に動かしてみるまでの手順を説明していきます.ただし,単に手順を無味乾燥的に示すのではなく,なるべくその背後にあるしくみや考え方についての説明も加えていきます.皆さんには,プログラムをコンピュータで実行するというのはどういうことなのか,といったイメージを是非とも掴んで頂ければと思います.
Hello worldプログラム
さて,これからつくるプログラムは世界一有名なプログラムと呼ばれているHello worldプログラムです.このプログラムは起動すると,標準出力に「Hello, world!」と出力して,終了するという単純なものです.プログラムは以下のようになります.
class MyFirstProgram { public static void main(String[] args) { System.out.println("Hello, world!"); } }
まずは,テキストエディタ(Windowsならメモ帳,Linuxならviやemacsなど)を用いて,上記のプログラムを記述したソースファイルを作成します.そして作成したファイルの拡張子をjavaとして適当な名前を付けて保存します(たとえば,Hello.javaなど).
# ここでは,とりあえずファイル名は適当で良いとしましたが,本格的なシステム開発では,1つのプログラムがたくさんのファイルから構成されるので,システムの構造を理解するうえでファイルの名前は重要になります.
# また,Javaの決まりとして,public なクラス名とファイル名は一致させなくてはならない,というものがありますが,これについてはまたの機会に説明することにします.
Hello worldプログラムの解説
さて,さきほどのHello worldプログラムを見てみると,classやpublicといったおまじないのようなキーワードが並んでいます.このまま先へ進んでも良いのですが,自分の書いたプログラムの内容を正しく理解することが,よいプログラマになるための第一歩でもあるので,ここでは,簡単にHello worldプログラムの解説をすることにします.個々の詳しい内容については本連載を通じて説明していく予定ですので,ここでは雰囲気だけを掴んでください.
まず,プログラムの1行目は,
class MyFirstProgram {
となっています.class(クラスと呼びます)というのはJavaのプログラムを作る上でもっとも重要な概念の一つであり,この連載でも詳しく説明していく予定ですが,ここではとりあえず,いくつかの関連する動作や状態を1つにまとめておく単位,と理解しておいてください.Hello worldプログラムでは,MyFirstProgramという名前のクラスを1つ定義しています.MyFirstProgramはクラス名であり,プログラマが自由に付けてよい名前です.そして,中括弧({と})で囲まれた以下の部分が,MyFirstProgramクラスの実際の中身となります.
public static void main(String[] args) { System.out.println("Hello, world!"); }
public static void main( ...とこれまたなにやら呪文のようなキーワードが連続していますが,一つ一つ解きほぐしていくことにしましょう.この部分ではmainメソッドと呼ばれるものを定義しています.メソッドとはプログラムの一連の処理をひとかたまりの動作としてまとめておく単位のことです.ただし,mainメソッドは特別な意味を持っていて,プログラムの実行開始時に最初に動き出す処理を定義します.すなわち,このHello worldプログラムを起動すると,ここで定義したmainメソッドの処理が実行されることになります.
mainの直後にある(と)の丸括弧で囲まれた部分String[ ] argsは,メソッドに対する入力(引数と呼びます)を定義しています.String[ ]は文字列の配列を示す型の名前(型とは何か,についてはそのうち説明します)で,argsは引数の名前になります.ここでは,メソッドに入力された複数の文字列をargsで受け取っていると考えてください.mainメソッドの引数は特別な意味を持っていて,プログラムの起動時にコマンドラインから渡した値が入力として渡されることになります.ただし,Hello worldプログラムでは,この引数は特に使わないので,今の時点ではあまり気にしないことにしましょう.
mainの直前にあるvoidはメソッドが返す値(戻り値)の型を示すものですが,mainメソッドは特に何の値も返さないので,値の無い型を意味するvoid型を指定しています.
つぎに,publicキーワードですが,これは,このmainメソッドがMyFirstProgramクラスの公開されたメソッドであることを示しています.公開されたメソッドはクラスの外から見えるようになります.逆にメソッドをクラスの外から見えなくするにはprivateキーワードを指定します.このようにJavaではクラスの中の要素(ここではmainメソッド)の公開,非公開の設定を行なうことができます.Hello worldのような単純なプログラムではあまり意味の無いような機能に思えますが,大規模なプログラムを複数人で開発するような場合,この機能は非常に重要になってきます.
最後にstaticキーワードですが,これはmainメソッドがクラスメソッドであることを示しています.クラスメソッドが何であるかについては,クラスとオブジェクトについて説明してからでないと理解が難しいかもしれません.とりあえずここでは,mainメソッドがMyFirstProgramクラスと直接結びついているメソッドだと思って下さい.
まとめると,public static void main(String[] args)の意味は,入力として複数の文字列を受け取り,値を返さない,MyFirstProgramクラスと直接結びついた,公開された,mainという名前のメソッド,といことになります.
さて,mainメソッドの中身は,その後の中括弧で囲まれた部分になります.
System.out.println("Hello, world!");
これは,Javaが提供しているSystemクラスの中にあるoutという要素(オブジェクト)に対して,printlnというメソッドを"Hello, world!"という文字列を渡して呼び出しなさい,という命令を表しています.この命令が実行されると,Javaのシステムは標準出力に,Hello, world!という文字列を印字します.セミコロン(;)は1つの命令を表す文の終わりを示すためのものです.
少々長くなってしまいましたが,以上がHello worldプログラムのざっとした説明になります.たったこれだけのプログラムの中に,たくさんの内容が詰まっているので,うんざりしてしまうかもしれませんが,それらの一つ一つについては,この連載を通じてじっくりと説明していきますので,少しずつ理解していって下さい.
プログラムのコンパイルから実行まで
さて,それでは早速さきほどのHello worldプログラムを実行してみましょう,と言いたい所なのですが,Javaの場合,プログラムを実行する前にソースコードをコンパイルする,という重要な手順が必要になります.これはJavaがコンパイラ言語の一種であり,ソースコードを一旦,機械(この場合,Javaの仮想マシンのプログラム)が直接読み込んで理解できる形式のファイル(一般にはオブジェクトコードと呼びます.Javaの場合は仮想マシンが実行するので特別にバイトコードと呼ばれます)に変換しなくてはならないからです.ソースコードをオブジェクトコードに変換するプログラムのことをコンパイラと呼びます.Javaコンパイラはjavacというコマンドで呼び出すことができます.
それでは実際にHello worldプログラムをコンパイルしてみましょう.さきほど作成したソースファイルの名前がHello.javaだとすると,そのファイルが置いてあるディレクトリ上で,以下のようにjavacコマンドを実行すればコンパイルできます.
javac Hello.java
コンパイルに成功すると,同じディレクトリの中にMyFirstProgram.classというファイルが作成されているはずです.これがJavaコンパイラが生成したバイトコードのファイル(クラスファイルと呼びます)です.ファイルの拡張子がclassになっていること,ファイルの名前がMyFirstProgramと,さきほど定義したクラス名と一致していることに注意してください.基本的に,Javaコンパイラはソースコードの中で定義したクラスごとに,「クラス名.class」という名前のクラスファイルを生成します.
# クラス定義がネストしている場合は話は違ってきますが,とりあえず.
コンパイルに失敗した場合は,行番号とともに何らかのエラーメッセージが出力されると思います.たとえば,ソースコードに全角の空白文字が含まれていたりすると,
Hello.java:3: \12288 は不正な文字です。 System.out.println("Hello, world!"); ^ エラー 1 個
のようなエラーメッセージが出力されます.
# 空白部分を半角スペースかタブを用いるようにしてください.
こんなときは該当箇所を修正して,再度コンパイルしてみましょう.エラーメッセージが出なくなれば大丈夫です.
ところで,このようにして作成したMyFirstProgram.classというファイルは,Javaの仮想マシンが読み込むための形式に変換されているので,テキストエディタで開いてみても,わけのわからないコードが表示されるはずです.一般的にバイトコードをプログラマが直接編集したりすることはしません.
さて,いよいよHello worldプログラムを実行してみましょう.Javaの仮想マシンのプログラム(javaコマンド)を,クラス名を指定して以下のように起動します.
java MyFirstProgram
実行に成功すると,以下のような出力が得られると思います.
Hello, world!
javaコマンドを起動すると,Javaの仮想マシンはコマンドラインの引数で指定されたクラスのクラスファイルを見つけてロード(読み込み)し,そのクラスで定義されている公開されたmainメソッドの実行を開始します.さきほどの例でいうと,Java仮想マシンはMyFirstProgram.classファイルを読み込んで,MyFirstProgramクラス内のmainメソッドを実行し,結果として標準出力にHello, world!という文字列が出力される,ということになります.
これでようやく,わたしたちの最初のJavaプログラムを動かすことができるようになりました.ところで,どうしてJavaのプログラムを実行するためには,こんなに面倒くさい手順を踏まなくてはならないのでしょう?
この疑問に答えるためには,まずプログラミング言語による実行方式の違いについて理解する必要があります.
世の中にはJava以外にも,CやC++, Smalltalk, PythonやRuby, Perl, Fortran, Lisp, Haskell, Prolog, ...などなど,それこそ星の数ほどのプログラミング言語があります.これらは言語の処理系の違いといった観点からコンパイラ型とインタプリタ型,という2つの種類におおざっぱに分類することができます.
コンパイラ型言語では,ソースコードをコンパイラによってコンピュータが理解できる形式のコード(ネイティブコードと呼んだりします)に変換し,そのコードをコンピュータが直接実行することによって,プログラムが動作します.CやC++, Fortranなどはコンパイラ型言語といえるでしょう.
一方のインタプリタ型言語では,インタプリタと呼ばれるプログラムがソースコードを少しずつ読み込んで,その意味を解釈していきながらプログラムを実行していきます.インタプリタ型の言語としては,BasicやPerl, Rubyなどがあります.インタプリタ型言語では,プログラムを実行するたびにソースコードを解釈しながら処理を実行していくので,コンパイラ型言語で書かれたプログラムに比べて,実行速度の面で不利になります.一方,いちいちコンパイルという手順を通さなくても,ソースコードをプログラムとして直接実行することができるので,ちょっと書いたプログラムをすぐに実行して試すことができる,という利点があります.また,コンパイラが出力したネイティブコードは,WindowsならWindows専用,inuxならLinux専用,MacならMac専用といった具合に,特定のプラットフォームに固有のものであり,他のプラットフォーム上では動作しませんが,インタプリタの場合には,インタプリタ自体がそのプラットフォームに対応していれば,ひとつのプログラムを他のプラットフォームでもそのまま動かすことが可能です.
# 実際のプログラムではプラットフォーム依存の処理とかもありますので,このような理想どおりにいかないこともありますが...
# また,コンパイラ型言語でも,ソースコードをそれぞれのプラットフォームに向けてコンパイルし直してやれば,いろいろなプラットフォーム上で動かすことも可能です.
# 概念的には,プログラミング言語とその処理方式は独立であり,CのインタプリタやRubyのコンパイラなどといったものも考えられるのですが,現実には言語の仕様は処理方式と密接に関係する場合が多いので,ある言語が決まるとどの種類の処理系になるのかが決まってきます.
さて,実をいうとJava言語は,インタプリタ型とコンパイラ型の間に位置しています(中間コード型).どういうことかというと,JavaのソースコードはJavaコンパイラ(javacコマンド)によって,いったんバイトコード(中間コードとも呼ばれます)に変換されます.この点はコンパイラ型と似ています.ただし,変換されたバイトコードはコンピュータが直接実行することはできなくて,Java仮想マシン(JVM)と呼ばれる一種のインタプリタプログラム(javaコマンド)によって実行されます.バイトコードはJava仮想マシンさえあれば,どんなプラットフォーム上でも動きます.さらに,あるバイトコードをネットワークでつながれた別のコンピュータに転送し,それを実行する,なんてことも可能になります.また,バイトコードは機械やプログラムで高速に処理できるように設計されているので,インタプリタ型言語よりも実行速度の面で有利になります.このように,中間コード型の言語はコンパイラ型とインタプリタ型のそれぞれの利点をいいとこどりしたような形になっていますが,その代償として,Javaのプログラムを実行させるためには,前述のような少々面倒くさい手順を踏まなくてはならなくなっているのです.
まとめ
以上,Hello worldプログラムの作成から,コンパイル,実行までの流れについて,一通り説明してきました.
ところで,今回はJavaにおけるプログラム作成から実行までの基本的な流れを理解するために,テキストエディタからコンパイラ,Java仮想マシンの実行まで,すべてコマンドラインから直接起動していくというやり方を紹介しましたが,実際の開発では,上記の作業をひとつのソフトウェア上から一貫して処理できるような統合開発環境(IDE)と呼ばれるものを使うことがほとんどです.代表的なものとして,たとえばEclipseやNetBeansなどがあります.これらのソフトウェアは無料で配布されているので,興味がある方は実際にダウンロードして使ってみることをお勧めします.この連載でも機会があれば紹介していくかもしれません.
オブジェクトとプログラミングの考え方
Java を扱っていると「オブジェクト指向」という言葉がついてくると言いましたが、これはなんでしょうか。
オブジェクト指向というのはプログラミングの考え方の一つなのですが、オブジェクト指向におけるオブジェクトとは何かという点についても議論を呼ぶ話題ではあります。
詳しく話し出せばアランケイやストラウストラップの名前を出していく必要が出てくるのですが、今回はメッセージ主体のオブジェクト指向で考えてみたいと思います。
オブジェクトとは「内部状態を持ち」「メッセージを受け取る」ことができるものとして話を進めます。
オブジェクトに対して話しかけると、それに合わせて動いてくれたりする。驚くべきことに、この2つを念頭に入れておくだけで、プログラミングにおける様々な表現ができるという考え方です。
iPod.startSound(); これは iPod というオブジェクトに対して「音鳴らせー」というメッセージを投げてみた例です。iPod が音を鳴らし始めます。
iPod.stopSound(); これは iPod というオブジェクトに対して「音止めろー」というメッセージを投げてみた例です。iPod が音を止めます。
iPod はどうやって音を鳴らしてるの?なんていうことは、呼びかける側には関係のない話です。
「動けー」と呼びかけて、期待通りに動いてくれれば、どんな風に動いていようが利用者の要求は満たされるのですから。
このように、オブジェクトには「メッセージ」に対応した振る舞いが定義されています。
iPod.break(); これは iPod に「壊れなさい」なんてメッセージを投げてみた例です。iPod が壊れてしまいます。
iPod.startSound(); iPod に「音を鳴らせー」とメッセージを再度投げてみました。しかし鳴りません。壊れているからです。
このようにオブジェクトは「状態」を保持することができ、状態に合わせて振る舞いを変化させることが可能です。
iPod.repair(); iPod に「なおりなさい」とメッセージを投げると直ります。
iPod.startSound(); iPod に「音を鳴らせー」とメッセージを投げると、今後はなってくれました。
壊れているのにメッセージを受け取れるなんて、と違和感がわくかもしれません。もしそう感じたならば、それはプログラマがよく言う「気持ち悪い」の一種とも言えます。
じゃあどういう風に振る舞ってくれてたら「美しい」のか。このように、オブジェクトを「役者」と考えるならば、その「振る舞い」を考えるのもプログラマの醍醐味です。
以上のように、状態と振る舞いを定義したオブジェクトに話しかけながら「シナリオ」を組み立てていくという、プログラミングの考え方を例に挙げてみました。
今度は、この考えたシナリオを「Java でどのように表現するのか」。
「プログラミングの考え方」を「言語の機能」で表現するのであり、Java はこの「オブジェクト」という単位を言語の機能としてサポートしてくれているため「オブジェクト指向言語」と呼ばれているわけです。
注意する点は、オブジェクト指向をサポートしているだけであって、他の考え方も可能ということです。実際、Java のオブジェクト指向というのはメッセージを意識して実装することも可能なのですが、データ型を意識した別のオブジェクト指向言語からの歴史も引き継いでいるため、この2つのオブジェクト指向の考え方を混ぜて考えてしまうと、綺麗にプログラムを書くことが難しくなってしまいます。
大事なのは、プログラミング言語は「思い描いた世界を表現するためのツール」であり、曖昧なまま実装に進まないでくださいということです。
# メッセージ主体のオブジェクト指向が表現しやすい言語として、Smalltalk や Ruby などが参考になると思います。
Java 開発環境のインストール on Windows
話を始める前に、まずは Java の開発環境を整えないと始まりません。
Java には、実行環境である JRE と開発環境である JDK が存在し、以下のサイトからダウンロードすることが可能です。
以下の説明は Java に限らず、大抵のソフトウェアをインストールするときと同様の流れになります。
1. JDK をインストールしてください。
2. 環境変数 JAVA_HOME を設定し、PATH に通しておくと便利です。
以下、丁寧すぎる紙芝居によるインストールの説明になります。必要のない方は読み飛ばしてください。
上記2行で説明は終わりなのですが、Windows のソフトウェアインストールに慣れていない、環境変数というものを初めて聞いたという人のための説明が以下になります。
逆にむずかしそうと思わせかねないくらい長いですが、上記2行を丁寧すぎる紙芝居付き説明しているだけです。
# 画像付きだとページ数が膨大になるから省略されているけど、初めて触る環境変数はちょっとこわい、書いてある通りにやったのに動かない、このあたりが初心者時代の最初の壁であったと覚えています。
さっそくインストールしていきましょう。
現在の最新版である JDK 6 Update 10 をダウンロードします。
JDK をインストールすると JRE も一緒にインストールされるので、ダウンロードする必要があるのは JDK だけです。
Windows 版を選択します。
License Agreement に agree して Continue を選択します。
「jdk-6u10-windows-i586-p.exe」をダウンロードすることができました。これが JDK のインストーラです。
インストーラを実行します。
基本的にはデフォルト設定のまま画面を進めていって問題ありませんが、一応一画面ずつ確認していきます。
最初はライセンスについて同意して次の画面へ進みます。
インストール先の選択です。
デフォルトで「C:\Program Files\Java\jdk1.6.0_10」に JDK がインストールされます。
JDK のインストール中です。のんびり待ちましょう。
しばらくすると、途中で JRE のインストール画面が現れます。
デフォルトのインストール先は「C:\Program Files\Java\jre6」です。
JRE のインストール中です。こちらものんびり待ちましょう。
インストール終了です。
JDK と JRE がインストールされたことを確認しましょう。
# 画像に ant や jruby 等が入っているのは書いてる人の環境ということで、新規にインストールされるのは jdk1.6.0_10 と jre6 だけで問題ありません。
「C:\Program Files\Java\jdk1.6.0_10\bin\java.exe」が Java アプリケーションを実行するときに使うものです。
「C:\Program Files\Java\jdk1.6.0_10\bin\javac.exe」が Java のソースコードをコンパイルするときに使うものです。
この2つを今後使っていくことになるので動作を確認しておきたいところですが、ダブルクリックで実行すると、一瞬コマンドプロンプトが出てくるだけで何が起こったか分からないと思います。
コマンドプロンプトから「C:\Program Files\Java\jdk1.6.0_10\bin\java.exe」を実行してみると、何が出力されたのか確認することができます。今回はバージョンを確認するために -version というオプションをつけて実行してみました。
これで java と javac が使えることが確認できれば、これから Java での開発を始めることができます。
しかし、毎回「C:\Program Files\...」と打つのは大変なので、java と打っただけで「C:\Program Files\Java\jdk1.6.0_10\bin\java」を実行できるようにしておきましょう。
環境変数というものを設定することが目的です。
コントロールパネルのシステムから「システムの詳細設計」を選択します。
「環境変数」を選択します。
システム環境変数に JAVA_HOME というものを作ります。
JAVA_HOME に 「C:\Program Files\Java\jdk1.6.0_10」と設定します。
これは、「あなたの環境で Java はどこにインストールされていますか?」ということを他のアプリケーションが知りたいときに参照します。
つまり、どこに Java がインストールされているか分からなくても、JAVA_HOME が設定されていれば 「%JAVA_HOME%\bin\java」を実行すれば動くことが保証されることになります。
続いて PATH に java の場所を追加します。
コマンドプロンプトで、ただ java とだけ打った場合、Windows は PATH に含まれている場所から java を探しにいきます。さきほどは PATH に追加していなかったため、「C:\Program Files\Java\jdk1.6.0_10\bin\java」とフルパスで打つ必要がありました。
「%JAVA_HOME%\bin」というのを PATH に追加すれば、java と打ったときに「%JAVA_HOME%\bin\」以下を探しにいってくれるようになります。
%JAVA_HOME% と書けるのは、先ほど設定したからであり、「C:\Program Files\Java\jdk1.6.0_10\bin」と書いても同様です。
PATH の区切り文字はセミコロンであるため、末尾に追加するときは「〜〜;〜〜;%JAVA_HOME%\bin」となります。
以上で PATH に通すことができました。コマンドプロンプトから、今度は 「java -v」とだけ打ってバージョンが確認ができれば問題ありません。
おつかれさまでした。
プログラミング初心者へ
本 Blog では、Sun Microsytems のプログラミング言語 Java を用いて、毎週月曜日「Java によるプログラミング入門」の記事を連載していきたいと考えています。
# 複数人で書いていくつもりなので語調は毎回変わると思います。
プログラミング言語の入門ということを考える際、2つの選択肢が生まれてきます。
一つはプログラミング経験者を対象に「言語の特徴やテクニック」を説明する入門、もう一つはプログラミング初心者を対象に「プログラミングという考え方」を説明する入門です。本 Blog では後者を対象としています。
# しかし最初から制限をつけても勢いが下がりそうなので順番やレベルはそのときの気分で…。
「プログラミングという考え方」を身につけるためには、何か一つの言語を題材に挙げなければならないという問題があります。一方、プログラム言語はそれぞれ思想や目的を持ち、現実の様々な問題に取り組むための複雑な機能を持ち合わせています。「プログラミングという考え方」と「言語の機能」の両方を同時に学ぶことは大変であるため、今回は「プログラミングという考え方」に焦点を当てて話していくつもりです。
Java の持つ強みの一つとして、豊富なライブラリが挙げられます。これは「表現のしやすさ」につながります。
また、Java というと「オブジェクト指向」という言葉(考え方)がついてくることになりますが、オブジェクト指向一つとっても「メッセージ」を意識したオブジェクト指向、「データ型」を意識したオブジェクト指向等、考え方は異なってきます。他にも「手続き型」や「関数型」といった考え方がありますが、Java はある特定の考え方に縛られることなく、思い描いた世界を表現しやすい言語であると考えています。
# 従って様々な異なる世界を思い描いてチームでプログラミングを行うと、ズレが生じてきやすい言語といえなくもなさそうですが。
Java を通して様々な考え方とその表現を紹介していき、理想は思い描いた世界をそのままプログラムの世界に表現できるようになるプログラミング入門書を目指します。