プログラミングは「習うより慣れろ」ということばがあてはまる世界です。解説をじっくり読むより、さっと読んで、サンプルをコンパイル・実行してみてください。説明は長いですが、プログラムそのものはとても短いものです。うまく動いたら、ごく簡単な改造をしてみてください。ポイントは「とにかくコンパイル・実行(できれば改造)」なのです。
そのうち、いろいろ、わかってくることと不思議に思えることがあらためて出てくることでしょう。そうなってから、今度はもう少しゆっくり解説を読んでみてください。
ごちゃごちゃした解説はとにかく、以下で紹介するInuSample.javaがわかれば今回は十分なのです。まず、それを目標にしてください。
Javaでは、次のような形をよく使います。
String name;
int x;
こうすると、nameは文字列の変数、xは整数の変数になるのでした。
ここで、Stringやintは、変数の種類を表すもので、一般に型とよばれるものです。型には、文字の型(char、なんか変ですが、文字と文字列は似て非なるものです)、実数の型(dobule他)などがあります。
逆に、変数の一般的な定義の仕方は、
型 変数;
ということになるのです。最初の例「String
name;」などと見比べてみてください。くどいですが、Stringが型で、nameが変数ですね。それで「nameはString型の変数」「xはint型の変数」などと言うのです。
しかし、ほかにもっと別の「もの」が必要な場合はどうすればよいのでしょうか。実は、Javaではプログラマ(つまり私たち)が勝手に作ってよいのです。メモリの中は小さいながら一つの世界です。その世界に私たちが作った「もの」(=オブジェクトといいます)を置くことができるのです。すばらしいですね。
というわけで、例として、「犬」をつくることにします。もちろん本当の犬は無理ですが、とりあえず、次のようなデータと動作を持つことにします。
犬:
データ:名前
動作 :鳴く
これは、「犬そのもの」というより、「犬の設計図」(「犬の型」と言います)です。これをJavaでは、クラスとして、たとえば、次のように書くことができるのです。
class
Inu
{
private String name;
Inu(String s){
name = s;
}
void naku(){
System.out.println("わん。僕は"
+ name + "だ。");
}
}
以下の説明は初心者にはそれほどすっきりしないかもしれません。なるべくわかりやすいように書いたつもりではあるのですが...。いずれにせよ、はじめは、とりあえず、細部にこだわらず、ざっと読んでおくだけでよいと思います。先に進むにつれてわかってくると思います。ただ、そのためには自分でコンパイル・実行と、サンプルの改造をする必要があります。
さて、解説です。まず、「犬」というものを定義するぞと、宣言しなければなりません。それが第1行目の
class Inu
です。クラス名に日本語文字を使うこともできますが、ここではInuとしました。これはInuというクラスを定義するということですね。
実は、クラスは、Javaプログラムの最初から出てきています(入門2を参照)が、第一義的には、自分が定義したい「もの」の設計図(=「オブジェクトの型」)なのです。ただし、クラスInuは、入門2以来使ってきた「mainを持つクラス」とは少し違うと感じるかもしれません。実際、「mainを持つクラス」はいわば「プログラムの中心を持つクラス」なので、Inuのようなクラスとは、(普通は)役割が少し違うのです。とは言え、同じクラスというものではあることにかわりはありません。
いずれにしても、ここでは、mainを持つクラス(これはあとで書きます)以外に、「犬」のクラスを考えているということなのです。
クラスInuの定義は、すぐ下の「{」から、最後の「}」までです。復習すると、
クラスは、
class クラス名 などと定義するものでした。 |
さて、「犬」は、名前を持つことにしました(「太郎」とか「ポチ」とか、個別の名前です)。今書いているのは、個別の「犬」ではなく、その設計図ですが、もちろん、設計図に「名前」の置き場所を書いておく必要があります。それが
private String name:
です。ちゃんとクラスの定義の中に書いてありますね。
privateは、「右に定義しているもの(今の場合は、name)はそのクラスにプライベート(非公開)なもので他のクラスのものはさわれない」という意味になります。これにより、nameは、クラスInuの外から直接操作できなくなるのです。なぜ、そんなことをするのかは、もう少し進んでから説明します。とりあえず、そんなものかと思ってください。また、ここでは使いませんが、逆に、他のクラスから自由に使えるという意味のpublicというキーワードもあります。
その下には、
Inu(String s){
name = s;
}
というものがあります。これがひとつのカタマリです。これは、「犬の設計図」には書きませんでしたが、コンストラクタという重要なもので、言わば「犬を創る機能」なのです。
「あれ、Inuってクラス名?コンストラクタ名?」と思ったなら、するどいです。コンストラクタというものは、クラスと同じ名前のものなのです。
Inuの後の丸カッコ「(」と「)」の間にある「String s」は、「このコンストラクタは文字列を外から受け取り、それをsで表わす」という意味です。そして、コンストラクタのすることは、後の中カッコ「{」と「}」の間に書きます。今の場合、それは「name = s;」ですが、これは「外から受け取った文字列(sで表わされる)をnameに代入する」ということです。文字列は、「=」で代入できるのです。(文字列に限らず、何でも、「=」は「代入」を表わします。)
これでクラスInuのコンストラクタの説明は終わりです。しかし、その使い方を見なければ、何のことだかさっぱりわからないと思います。「外から受け取る」ってどういう意味だろう、とか。これは、少し後で実例をお見せしますので、それまでちょっとシンボウしてください。たぶん、見れば「使い方」(もしくは「使われ方」)はすぐにわかると思います。それがわかりさえすればよいのです。
もう少しクラスInuの説明を続けましょう。コンストラクタの次には
void naku(){
System.out.println("わん。僕は"
+ name + "だ。");
}
と書いてあります。これは、最初の「犬の設計図」で考えた「動作:鳴く」に相当する部分です。
実は、Javaでは何かするものをメソッドといいます。その言い方をすれば、これは、「犬が鳴くメソッド」(「犬を鳴かすメソッド」)なのです。(コンストラクタは、「特殊なメソッド」ということもできると思いますが、一般には区別します。)
はじめにあるvoidは、このメソッドが「何も報告せずに終わる」という意味です。...そう言われても、初心者にはなんだかわかりませんよね。とても嫌だと思いますが、しばらくはがまんして、単純なメソッドの頭にはvoidがつくんだな、と思っておいてください。
そして、nakuがこのメソッドの名前です。その後の丸カッコ「(」と「)」の間が空なのは「データを外から何も受け取らない」ということです。コンストラクタは文字列を受け取るようにしましたが、nakuは何も受け取らないようにしたのです。
naku()のあとの「{」と「}」の間にある処理が、「このメソッドがすること」です。これは、つまり、「わん。僕はname(つまり、名前)だ。」と画面に出力するということですね。(この犬は本当に声をだすようにはしていません。念のため。)
なお、コンストラクタやメソッドが「外から受け取るデータ」のことを、一般に、引数といいます。これからこの言葉も使いますので覚えておいてください。この言葉を使うと、「コンストラクタは引数を取る」「nakuは引数を取らない」などとなります。
どうもややこしいですね。でも、上のコードをもう一度見てください。書いてある文字数はほんのわずかです。はじめはこれを丸写しにして使ってみてください。
さて、クラスInuができました。これは、最初に書いたように「犬の設計図」です。設計図というものは、普通は、それ自体では何にもなりません。「実体」ではないからです。一般には、設計図をもとに「実体」を作り、それを使うのです。
クラスから生成する「実体」を、業界では、インスタンスとかオブジェクトといいます。クラスInuを書いたから、次は、そのオブジェクトを生成し、それを使うコードを書く必要があるわけです。オブジェクトの生成(と「名前付け」)は、たとえば、
Inu d;
d = new Inu("太郎");
のようにできます。このように書くと、Inuの実体(オブジェクト)が生成され、dがそれを表わすようになるのです。
とは言え、これだけではよくわからないはずです。まず、このクラスInuを使った簡単な(あほな)プログラムを紹介します。このプログラムを見て考えましょう。
//InuSample.java
class Inu
{
private String name;
Inu(String s){
name = s;
}
void naku(){
System.out.println("わん。僕は"
+ name + "だ。");
}
}
class InuSample
{
public static void main(String[] args){
Inu d;
//Inu型変数dの用意
d = new Inu("太郎");
//Inuオブジェクトの生成
d.naku();
//メソッドnakuの実行
}
}
普通に動くプログラムにするためには、「mainを持つクラス」が必要です。ここではそれをInuSampleとしました。混乱を避けるため、「mainを持つクラス」の名前とプログラム名(拡張子を除く)を同じにしていることに注意してください。プログラム名は最初にコメントの形で書いています。
それから、とりあえず、実行画面も先に見ておきましょう。
Fig.1 InuSampleのコンパイルと実行。
それでは、プログラムInuSample.javaの説明をします。
はじめのほうにクラスInuの定義がありますね。これは、上で説明したものと同じです。同じですから、今はあまり見ないで、下の「mainを持つクラス」InuSampleを見てください。くどいですが、一般的なJavaのプログラムでは、「mainを持つクラス」が必要なのでした。そのmain(プログラムの中心部分)の中で、クラスInuを使っています。悩まずに、その使い方を見てください。
まず、mainの最初の行「Inu d;」では、Inuオブジェクトを扱うための変数dを用意しているのです。こう書くとdが「Inu型の変数」になるのです。この段階で、Inuオブジェクトはありません。そういうものなのです。
そして、2行目の「d = new Inu("太郎");」が今日のハイライトです。これで、「太郎」という名前を持ったInuオブジェクトが生成され、d(というInuの変数)がそのオブジェクトを表すようになるのです。
どういうことかと言うと、2行目のように書くと、
1.右辺の「new
Inu("太郎")」で、Inuオブジェクトが生成され、そのときにInuのコンストラクタが実行される。
そのコンストラクタは「"太郎"」というデータを受け取る。
2.そして、dがそのオブジェクトを表すようになる。
ということなのです。
ここで、「"太郎"」が、「コンストラクタが外から受け取る文字列」つまり「引数」になるのです。(「外からデータを受け取る」とはこういうことだったのです。)
よく見ると「new Inu("太郎")」の「Inu("太郎")」は、コンストラクタ「Inu(String
s)」と同じ(ような)形になっていますよね。クラス定義内のコンストラクタのところを見てください。丸カッコの中にStringがあるところが同じ形であるわけです。つまり、「new
Inu("太郎")」は、「"太郎"を引数にしてコンストラクタを実行」という意味なのです。
「コンストラクタを実行」とは、「その定義に書いた内容を実行する」ということです。Inuのコンストラクタでは、引数に与えられた文字列(今の例では「太郎」。コンストラクタの定義内ではsで表わされる)をこのオブジェクトのnameに格納するということになります。(nameは「犬」の設計図Inuに書いてあるので、すべてのオブジェクトが内部に持つことになるのです。)
Fig.2 オブジェクトの生成とコンストラクタ
そして、3行目の「d.naku();」は、「dが表わすInuオブジェクトに対してnakuを実行」という意味です。これはもちろん、メソッドnakuの定義の中身の実行です(面倒がらずにnakuの定義を見てください)。今、dの表わすInuオブジェクトのnameには「太郎」が格納されているので、nakuを実行すると「わん。僕は太郎だ。」と出力されるわけです。
もう一度、mainの中を見てください。要するに、これがクラスInuの使い方なのです。
さて、先に進む前に、1つコメントさせてください。「dがオブジェクトを表す」と書きました。実は、Javaでは、d(つまり変数)は、オブジェクトそのものではなく、「オブジェクトを指し示すもの」なのです。
Fig.3 変数は、オブジェクトを指し示す
(オブジェクト内にnameがある)
今のところ、あまり重要ではなさそうです(もちろん、本当は重要なのです)が、なんとなく頭に入れておいてください。そして、「変数dがオブジェクトを表す」というより「変数dがオブジェクトを参照する」という方が普通の用語法なのです。「参照する」を普通の日本語で考えるとかえって分かりにくいと思いますが、要するに「指し示す」ということです。(注:あまり他の言語との比較を書きたくないのですが、Javaでクラスのオブジェクトを扱う変数は、C++で言うと、「普通の変数」というより、ポインタとか参照変数に近いものです。C++を知らない方は、気にしないでください。)
ついでに言うと、普通「変数を用意する」は「変数を定義する」、「メソッドを実行する」は「メソッドを呼び出す」などと言います。このような言い回しも使っていきますので、おぼえるようにしてください。
上に書いた「オブジェクトの生成」を一般的に書いておきましょう。つまり、 変数 = new クラス名(あれば引数); というコードを書くと、「右辺でオブジェクトが生成され、コンストラクタが実行され、左辺の変数がそのオブジェクトを参照する(指し示す)ようになる」のです。右辺で「クラス名」と書いたものは、「コンストラクタ」とも言えます。また、引数がある場合は、コンストラクタ実行時に、コンストラクタに渡されることになっています。 |
メソッドの使い方も書いておきましょう。これは、つまり、 変数.メソッド(あれば引数); というコードを書くと、この変数が参照する(指し示す)オブジェクトに対して、メソッドが実行されるということです。(「d.naku();」では、dが変数、nakuがメソッドで、その引数は「なし」です。) |
ところで、InuSampleというクラスのオブジェクトは、生成していないことには気が付きましたが?実はmainもメソッドなのですが、これはオブジェクトを生成しなくても、javaコマンドで実行されることになっているのです。それは、そういうものだと思ってください。
あとコメントが少々。Inu型の変数dの定義(用意)と、Inuのオブジェクトの生成は、
Inu d;
d = new Inu("太郎");
と書きましたが、これらは、まとめて、次のような1行で書くこともできます。
Inu d = new Inu("太郎");
これは入力のときに使った「BufferedReader br = new BufferedReader(...);」と同じ形ですね。実際、同じ仕掛けなのです。違いは、Inuは私たちが作ったクラスであるのに対し、BufferedReaderはJ2SDKの中に用意されているクラスだというだけです。
さらに、用語をもう1つ。nameのようなオブジェクトのデータを表わす変数は、フィールドとよぶことになっています。私自身、最初は、この用語にものすごくなじめなかったのですが、みなさんはいかがでしょう。はじめはなじめなくても重要な用語なので、おぼえて使うようにしましょう。すぐに慣れると思います。
InuSample.javaでは、Inuオブジェクトの生成時に、決められた文字列「太郎」を与えるようにしましたが、これをユーザが決めるようにもできます。それには、入門3を思い出してください。たとえば、プログラムを次のように書くことができます。
//InuSample2.java
import java.io.*;
class Inu
{
private String name;
Inu(String s){
name = s;
}
void naku(){
System.out.println("わん。僕は"
+ name + "だ。");
}
}
class InuSample2
{
public static void main(String[] args)
throws IOException{
System.out.println("犬の名前を入力してください。");
String s;
//BufferedReaderオブジェクトを生成しbrで参照するようにする
BufferedReader br =
new BufferedReader(new
InputStreamReader(System.in));
s = br.readLine(); //sにユーザの入力文字列を格納
Inu d = new Inu(s);
//sをInuのコンストラクタの引数にする
System.out.println("犬がメモリ上に生成されました。");
System.out.println("その犬が鳴きます。");
d.naku();
}
}
Fig.4 InuSample2の実行例
今回のプログラムも「何の役に立つんだ」と言われれば身もふたもありませんが、メモリ上に生成された犬たちのことを思いつつ幕としましょう。
今日の内容を、今日、すみずみまで理解できなければいけないということはありません。そんなことで苦しむより、上のサンプルを改造して「猫」をメモリ上につくってみてください。それができれば十分なのです。次回は今回の話の補足をします。それでは、また。