Javaはオブジェクト指向の言語です。と言うことで、Javaの世界の本当の意味を知るためには、オブジェクト指向の考え方を学ぶ必要があります。ここまで、条件分岐と繰り返しの構文を学び、その後で、staticなメソッドについて学びました。この先のオブジェクト指向については、考え方ががらっと変わるように感じられるかもしれない…理解するために苦労するかもしれない、ということで、そこそこの覚悟をお願いします。分かれば簡単なことなのです。分かるまでが少し苦労するかもしれません。
オブジェクト指向とは、メソッド中心主義ではなくて、オブジェクトを中心に扱う考え方のことです。言い換えれば、メソッドに対してデータを流し込む(Mathクラスのメソッドや、これまで製作してきた staticなメソッドのように)に対して、オブジェクト(データ)が中心にあってそこにメソッドがくっついている、という考え方のことです。
さて、オブジェクト指向を理解するにあたって、幾つかの言葉を覚える必要があります。次の項でその言葉を定義してみようと思います。
具体例もなく言葉が登場しても分かりづらいでしょうか、以下の 5つの言葉とその意味を覚えてしまってください。
それぞれの言葉について、以下に解説していきます。
これまで製作してきたプログラムでも実はクラスを作ってきました…ただオブジェクト指向ではなかったけどね。さて、クラスをひとつ作成するための予約語はclass
です。製作中のプロジェクトのソースコードを見て、予約語class
の数を数えれば、そのプロジェクトで何個のクラスを宣言したかが分かります。
クラスの名称は型の名称になり、クラスの中身はインスタンスの基盤になります。戸建住宅に例えれば、住宅の設計図にあたるものがクラスになります。
クラスを基盤にして作られた実体のことをインスタンスと言います。住宅に例えれば、設計図に従って設計された住宅そのものがインスタンスになります。1つの設計図から同じ間取りの住宅を何棟も建設できるように、1つのクラスから複数のインスタンスを作成することが可能です。
クラスを基盤にしてインスタンスを作成するための予約語はnew
です。プログラムの流れを追いながら予約語new
を見ていくことで、どのタイミングで何個のインスタンスが生成されたか把握することができます。
インスタンスは、後述するインスタンスフィールドとインスタンスメソッドをそれぞれ 0個以上持っています。
インスタンスフィールドとは、インスタンスが持っているフィールド…変数のことです。
文法的には、staticがついていないフィールドということになります。
インスタンスメソッドとは、インスタンスが持っているメソッドのことです。
文法的には、staticがついていないメソッドということになります。
コンストラクタは、予約語によって、クラスからインスタンスが作成される際に、必ず呼び出される場所のことです。メソッドのような形をしていて、その中に処理を記述することができます。主に、インスタンスの初期化処理を記述します。
さて、オブジェクト指向を理解するために、Pointクラスを利用して行こうと思います。まず、Pointクラスの説明書(API)を眺めてみようと思います。まずは、数を数えられることが大切です。Pointクラスで宣言されているコンストラクタ、インスタンスフィールド、インスタンスメソッドの数を数えてみましょう。復習も兼ねて、staticなメソッド、staticなフィールドの数も数えてみましょう。Java SE 7(Java 1.7)の Pointクラスの説明書(API)を見てみることにします。次のリンクをクリックしてください→Pointクラス。Java 1.7の場合、これらの正解は以下の通りです。
正解できたでしょうか。数が数えられるということは基本中の基本です。もし不正解だったら、改めて良く考えてみて、納得してください。ここで数が数えられないと、きっと後で混乱します。
基本型変数は、名前のついた箱が用意されているイメージでした。例えば、以下は基本型のローカル変数を作成した例。
int a = 1; double b;
このイメージは以下のような感じです。
基本型変数は「名前のついた箱であり、その箱の中に値を入れることができる」ことが重要な点です。
Point型の参照型変数を初めて作成してみます。以下は参照型のローカル変数を作成した例。ローカル変数で、かつ初期値を決めていないので値は未定義状態となっています。
Point p;
このイメージは以下のような感じです。
参照型変数は「箱ではない」ことに注目してください。その意味では基本型とはまったくの別物です。少し後で解説しますが、「参照する」という言葉のとおり、名前と矢印の組み合わせで表現されます。
Point型のインスタンスを初めて作成してみます。予約語new
を使用していることに注目してください。
new Point();
このイメージは以下のような感じです。
Point型はインスタンスフィールド x, yを持つため、この図のようになります。また、インスタンス自体には名前がない…つまり名無しであることにも注意してください。
先の項でインスタンスに名前が無いと書きました。ところが、名無しのままでは、事実上、利用することができません。そこで、参照型変数とインスタンスを組み合わせることにします。それが以下。
Point p = new Point();
このイメージは以下のような感じです。
インスタンスが参照型変数に紐づけられることによって、実質的に、名前が与えられたことが分かるかと思います。
参照型変数とインスタンスを使用したソースコードは以下の通り。
H101/H101.java
(14行目に黄線が生じますが問題ありません)
import java.awt.Point; /** * 参照型変数とインスタンスを使用します。 */ public class H101 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { // インスタンスを生成し、参照型変数に紐づける Point p = new Point(); } }
このプログラムは実行しても何も起こりません。
mainメソッドの中で、1個の参照型のローカル変数が宣言され、また 1個の Point型のインスタンスが生成され、そのインスタンスが参照型のローカル変数に紐づけられたという動きを理解できるでしょうか。
1行目に import文を記述することを忘れないようにしてください。また、このimport
は「control + O」によって自動的に補完することもできます。なお、import文については、もう少し先の章にて詳細を解説していきます。
参照型変数やインスタンスをどのように用いていくかは、この後で解説していきます。
基本型変数の代入「=」と参照型変数の代入は、根底では同じことなのですが、実質的にはまったく異なったような振る舞いをします。後で混乱するもとになるので、ここで改めてしっかりと書いておきます。
以下の例にして、改めてその違いを図にしてみますね。
int a = 1; Point p = new Point();
参照型は、紐付ける…言い換えれば「参照する」ということに注目してください。
参照型変数は、どこかのインスタンスに紐付けられる。ローカル変数の場合には未定義状態があるけれど、それとは別に、どのインスタンスにも紐づけられていないことを明示的に示すための言葉がnull
です。これは予約語に準じる語となっています(予約語に準じる語は、trueと false と nullの 3つですべてです)。
nullの使用方法は以下のような感じです。
Point p = null;
このイメージは以下のような感じです。
Javaのクラス・インスタンスと、C言語の構造体・構造体の型とはある程度似通っています。
ほとんど同じと似ているところは以下の通り。
決定的に異なる点は 2つ。
C言語には、基本型と構造体について 4つの組み合わせがあります。
通常変数 | ポインタ | |
---|---|---|
基本型 | 基本型の変数 | 基本型のポインタ |
構造体 | 構造体の変数 | 構造体のポインタ |
このうち、Javaでは、「基本型の変数」と「構造体のポインタ(=参照型)」の 2つしか使用できません。C言語における「構造体のポインタ」は、Javaでの参照型と同じような感じです。言い換えれば、Java言語では、参照型変数にはポインタを表す接頭辞「*」が省略されているとも言えます。つまり、Java言語では、参照型は常にポインタなので、「*」を記述する必要がないのです。そして、構造体自体(Javaで言うところのインスタンス)を作るためには、Javaでは予約語new
を使用します。
また、C言語では、以下のようにポインタに直接番地を指定することが可能でした。動作するマシンのハードウェアの仕様を理解した上でないとプログラムが暴走する可能性があるとは言え、指定すること自体は可能でした。
int *p; p = 2000; /* ポインタ pは 2000番地を参照する */
しかし、Javaでは、参照型に対して直接番地を指定することはできません。