Javaはクラス抜きでは語れません。まずクラスの基本をしっかりと理解しましょう。
Javaでプログラムを作成するときは、必要なデータや処理をひとつのまとまりに記述します。このまとまりがクラスであり、このクラスを組み合わせてプログラムを組み立てていきます。
データや処理をどのようにまとめるか、「まとめたもの」(=オブジェクト)をどのように組み合わせるかなどを思考することが、俗に言う「オブジェクト指向」と呼ばれる考え方で、Javaは「オブジェクト指向型言語」と言われています。
クラスは次の要素で構成されています。
例としてSample0101.javaをメンバ変数とメソッドを解りやすく明示させたものを次に示します。
・クラスサンプル(Sample0601.java)
public class Sample0601 { static String str = "Hello World"; // メンバ変数 public static void main (String[] args) { // メソッド System.out.println(str); } }
クラスの書式は次の通りです。
[アクセス修飾子] [修飾子リスト] class クラス名 {
}
※修飾子については「修飾子の詳細」を参照してください。
メンバー変数とはクラス内で保持するデータを定義するものです。
メンバ変数の書式は次の通りです。
[アクセス修飾子] [修飾子リスト] 型 変数名;
※修飾子については「修飾子の詳細」を参照してください。
メンバ変数へアクセスするには次のように「.」(ドット演算子)を使用します。
クラス.メンバ変数;
※アクセス修飾子に注意してください。例えば「private」では上記のようにクラス外からアクセスできません。
メソッドは処理を記述することができ、クラスに機能を与えるものです。
メソッドの書式は次の通りです。
[アクセス修飾子] [修飾子リスト] 戻り値の型 メソッド名(引数リスト) { }
※修飾子については「修飾子の詳細」を参照してください。
※戻り値が無いときは「void」を記述します。
※引数リストは省略可能です。
引数リストの形式は次のようになります。
型 変数1, 型 変数2, ・・・
メソッドの使用方法は次のように「.」(ドット演算子)を使用します。
クラス.メソッド(引数リスト);
※アクセス修飾子に注意してください。例えば「private」では上記のようにクラス外からアクセスできません。
Javaでは「メソッド」をメソッド名で一意とするのではなく、「メソッド名+引数リスト」(この組み合わせを「シグニチャ」といいます。)で一意とする仕様になっています。つまり「引数の型」や「引数の数」が異なれば同じ名前のメソッドを複数作る事が出来るわけです。
同じメソッド名で「引数リスト」のみが異なるメソッドを用意する事をメソッドの「オーバーロード」といいます。
・オーバーロードのサンプルソース(Sample0602.java)
public class Sample0602 { public static void main(String[] args) { Sample0602.load("a"); // ちなみに自クラスのメソッドの時は次のようにクラスを指定せずに呼び出せます。 load("a"); load("a", "b"); // 引数の数が違う場合。 load(1); // 引数の型が違う場合。 } public static void load(String s) { System.out.println("「load(String s)」が呼ばれました。"); } public static void load(String s1, String s2) { System.out.println("「load(String s1, String s2)」が呼ばれました。"); } public static void load(int i) { System.out.println("「load(int i)」が呼ばれました。"); } }
・実行結果
C:\dev\java>javac Sample0602.java [Enter] C:\dev\java>java Sample0602 [Enter] 「load(String s)」が呼ばれました。 「load(String s)」が呼ばれました。 「load(String s1, String s2)」が呼ばれました。 「load(int i)」が呼ばれました。
クラスには上記例のような使用方法もありますが、オブジェクト指向本来の威力を発揮する主要な方法が別にあります。
それはクラスから「インスタンス」を生成して利用する方法です。「インスタンス」はそれ自身を型として取り扱う事ができるので、メンバ変数の値が異なる「インスタンス」を複数作成する事も可能です。
正に「物」として取り扱う事が出来るようになることからJavaでは「インスタンス」と「オブジェクト」は同意語として取り扱われています。
インスタンスを生成するには「new」演算子を使用します。書式は次の通りです。
・インスタンス生成の書式
インスタンスの型 インスタンス変数 = new クラス名(引数リスト);
※「インスタンスの型」とはインスタンス自身の「クラス」の他、その「親クラス(スーパークラス)」や実装している「インターフェース」になります。
インスタンスの「メンバ変数」と「メソッド」はそれぞれ、「インスタンス変数」、「インスタンスメソッド」と呼ばれます。
アクセス方法は、クラスのときと同様に「.」(ドット演算子)を使用します。
・メンバ変数の呼び出し
インスタンス.メンバ変数;
・メソッドの呼び出し
インスタンス.メソッド名(引数リスト);
インスタンスとは具体的にどのようなものか次のプログラムを例に見ていきます。
生徒クラス(Sample0603Student)からインスタンスを2つ生成して、それぞれに名前を設定します。各インスタンスを独立して取り扱っているところがポイントです。
・サンプルソース(Sample0603.java)
1 : public class Sample0603 { 2 : public static void main(String[] args) { 3 : // インスタンスの生成 4 : Sample0603Student student1 = new Sample0603Student(); 5 : Sample0603Student student2 = new Sample0603Student(); 6 : // それぞれのインスタンスに名前を設定 7 : student1.setName("Yamamoto Ichiro"); 8 : student2.setName("Yamada Hanako"); 9 : // それぞれのインスタンスから名前を取得 10 : System.out.println(student1.getName()); 11 : System.out.println(student2.getName()); 12 : } 13 : } 14 : 15 : class Sample0603Student { 16 : public String name = ""; 17 : public void setName(String name) { 18 : this.name = name; 19 : } 20 : public String getName() { 21 : return name; 22 : } 23 : }
※実際のソースには行数は入りません。
・4,5行目
生徒クラス(Sample0603Student)からインスタンス(student1、student2)を生成しています。
・7,8行目
インスタンスのメソッド(インスタンスメソッド)「setName」を呼び出して、それぞれのインスタンス変数に名前(Yamamoto Ichiro、Yamada Hanako)を代入しています。このようなメンバ変数へアクセスするためのメソッドは「アクセサ」※1とも呼ばれています。
・10,11行目
インスタンスメソッド「getName」を使用してそれぞれのインスタンス変数に代入されている名前を取得して出力しています。
このようにそれぞれのインスタンスが独立して機能しているところがポイントです。※2
・18行目
「this.name」の「this」は自身を示す特別なインスタンスです。通常は自身のインスタンス変数やインスタンスメソッドを呼び出す場合は「this.」を省略できますが、ここではメンバ変数の「name」と引数の「name」が同じで区別ができない為、インスタンス変数に付加する必要があります。
※1「アクセサ」の中でも、7,8行目で使用されているようにメンバ変数へ値をセットするものを「セッター」、反対に10,11行目のようにメンバ変数から値を取り出すものを「ゲッター」と言ったりします。
※2この例だけだとあまりありがたみが分からないかもしれませんが・・・
・実行結果
C:\dev\java>javac Sample0603.java [Enter] C:\dev\java>java Sample0603 [Enter] Yamamoto Ichiro Yamada Hanako
Javaには「コンストラクタ」という特別なメソッドが用意されています。コンストラクタはインスタンス生成時、つまりクラスを「new」したときに呼び出されます。インスタンス生成時に呼び出されることから、よくインスタンスの初期化処理に利用されます。
ちなみにC++にはインスタンスが破棄される時に呼び出される「ディストラクタ」と呼ばれるメソッドがありますが、Javaではインスタンスの破棄はJVMが管理しておりプログラムで制御できない為「ディストラクタ」は用意されていません。
コンストラクタの条件は次の通りです。
よってコンストラクタの書式は次のようになります。
class クラス名 { [アクセス修飾子] クラス名(引数リスト) { } }
また、コンストラクタも通常のメソッドのように「オーバーロード」することができます。コンストラクタの場合、呼び出されるのはインスタンス生成時ですから「new」するときに指定された引数の形式により、コンストラクタの呼びわけが行われます。
コンストラクタのサンプルとして上記のサンプル(Sample0603.java)をコンストラクタを使用したものに変更します。
上記サンプルではインスタンスメソッド「setName」で名前を代入していましたが、この場合「setName」メソッドで名前をセットされるまでは名前のないインスタンスが存在してしまいます。そこでコンストラクタでインスタンス生成時に必ず名前をセットするように変更します。
・サンプルソース(Sample0604.java)
public class Sample0604 { public static void main(String[] args) { // コンストラクタで名前を設定するように変更。 Sample0604Student student1 = new Sample0604Student("Yamamoto Ichiro"); Sample0604Student student2 = new Sample0604Student("Yamada Hanako"); System.out.println(student1.getName()); System.out.println(student2.getName()); } } class Sample0604Student { public String name = ""; // コンストラクタを追加。 public Sample0604Student(String name) { this.name = name; } public String getName() { return name; } }
・実行結果
C:\dev\java>javac Sample0604.java [Enter] C:\dev\java>java Sample0604 [Enter] Yamamoto Ichiro Yamada Hanako
最後にインスタンス生成に関して特殊な例を紹介しておきます。
インスタンスを生成するには「new」演算子を使用すると説明しましたが。主に次のような場合、「new」を記述せずにインスタンスを使用することができます。
1. String型を使用するとき。(「new」して生成することも可能です。)
String s = "「new」してません。";
2. 配列の初期化するとき。(初期化時以外は「new」が必要です。)
int arry[] = {1, 2, 3};
3. 基本データ型のラッパークラスに対するオートボクシング(Autoboxing)機能による自動変換のとき。(J2SE5.0以降)
Integer i = 0;
ここで「クラス」と「インスタンス」について整理します。
クラスとインスタンスの関係は、他でもいろいろと(「たいやきの型」と「たいやき」など)例えられたりしますが、ここではパソコンを例に説明したいと思います。
パソコンには作られた時点でCPUやメモリーなどの性能(スペック)が備わっています。パソコンはOSにより挙動が変化します。
この場合「クラス」と「インスタンス」の関係は次のようなイメージで表現できます。
つまりメンバー変数ごとに挙動を変えるものとして取り扱いたい場合、上記の例ではOSにより「Winパソコン」、「Macパソコン」、「Linuxパソコン」といった物(オブジェクト)がインスタンスであり、インスタンスの処理になります。反対にメンバー変数等により挙動を変化させる必要がない(インスタンスを生成する必要がないとも言えます。)の場合にはクラスで処理を行います。
プログラムソース上でのクラスに緋づく「メンバ変数」及び「メソッド」とインスタンスに緋もづいている「メンバ変数」及び「メソッド」の違い(見分け方)は「static」キーワードが付いているか否かです。まとめると次のようになります。
クラス | インスタンス | |
メンバ変数 |
・「static」修飾子を付けます。 ・「クラス変数」、または「static」(静的)を付与することから「スタティック変数」とも呼ばれます。 |
・「static」修飾子を付けません。 ・「インスタンス変数」とも呼ばれます。 |
メソッド |
・「static」修飾子を付けます。 ・「クラスメソッド」、または「static」(静的)を付与することから「スタティックメソッド」とも呼ばれます。 |
・「static」修飾子を付けません。 ・「インスタンスメソッド」とも呼ばれます。 |
実際のソースは次のようになります。
・サンプルソース(Sample0605.java)
public class Sample0605 { public static void main (String[] args) { Sample0605Pc pcW = new Sample0605Pc("Win"); //「Winパソコン」インスタンス Sample0605Pc pcM = new Sample0605Pc("Mac"); //「Macパソコン」インスタンス Sample0605Pc pcL = new Sample0605Pc("Linux"); //「Linuxパソコン」インスタンス System.out.println(pcW.execOs()); System.out.println(pcM.execOs()); System.out.println(pcL.execOs()); System.out.println(Sample0605Pc.isSpec()); //「パソコン」クラスの処理。 } } class Sample0605Pc { private String os = ""; // インスタンス変数 private static String spec = "【スペック】CPU:1GHz Mem:1GB HD:500GB"; // クラス変数 public Sample0605Pc(String os) { // コンストラクタ this.os = os; } public String execOs() { // インスタンスメソッド return "「" + os + "」パソコンを起動しました。"; } public static String isSpec() { // クラスメソッド return spec; } }
・実行結果
C:\dev\java>javac Sample0605.java [Enter] C:\dev\java>java Sample0605 [Enter] 「Win」パソコンを起動しました。 「Mac」パソコンを起動しました。 「Linux」パソコンを起動しました。 【スペック】CPU:1GHz Mem:1GB HD:500GB