【未経験からのプログラミング講座】STEP3.クラスとオブジェクト1

Pocket

1. オブジェクト指向プログラミング

1.1. クラスの構成

Javaでは、プログラムの一つ一つを「クラス」と呼びます。

Javaのコードには必ず1つ以上の「クラス」が存在しなければなりません。「クラス」を使用する時は現実の世界に存在する、「モノ」の概念に着目していきます。例として、「列車」といったモノについて下記サンプルコードを用いて、クラスを考えてみることにします。

クラス」は、先頭にclassというキーワードがつき、一番外側をブロック({ })で囲んで記述します。サンプルコードでは、列車クラスを作成しています(①)

また「クラス」には性質を定義しますが、性質は主に2種類あります。それが、「フィールド」と「メソッド」です。列車は、4両や8両といった車両数を持ち、赤や青といった色を持っています。このように、列車(クラス)についての性質をまとめた部分を「フィールド」といいます(②)

また、列車の車両数と色を決定し、それらを表示するといった列車(クラス)についての機能をまとめた部分を「メソッド」といいます(③)

またこれらの「フィールド」や「メソッド」をそのクラスの「メンバ」といいます。 クラスとは、このようにモノの性質や、その機能をまとめながら、プログラムを作成していくために使う概念なのです。

(ア) サンプルコード(例:列車クラス)

問題 3-1-1

フィールドとメソッドを各1つずつ持つ「TestClass」を作成してみよう。
フィールドの型、メソッドの処理内容は問いません。

1.2. コンストラクタの定義

コンストラクタとは、そのクラスのオブジェクトが生成された時に定型処理をクラスの機能として、一度だけ実行してくれる特別なメソッドです。

コンストラクタは、

・ クラスのオブジェクトを生成(インスタンス化)された時に一度だけ実行される。
・ クラスと同じ名前で宣言する。
・ 戻り値を設定しない(できない)。

といった特徴を持つメソッドです。

ただ普通のメソッドとは違って、コンストラクタは自由に呼び出して実行したりすることは出来ません。そのため、コンストラクタはオブジェクトのメンバに自動的に初期値を設定するといった処理を記述するのが一般的とされています。

(イ) サンプルコード(例:列車クラス)

問題 3-1-2

何らかの処理を行うコンストラクタを持つ「TestClass」クラスを作成してみよう。

1.3. メンバ変数の定義と初期化

変数には、主にメンバ変数ローカル変数があります。

ローカル変数とは、各メソッド(コンストラクタ)内で定義された変数のことです。他のメソッド(コンストラクタ)からアクセスすることはできません。次に、メンバ変数とは、クラス内で定義された変数のことです。ローカル変数とは違い、そのクラス内であればどのメソッド(コンストラクタ)からでもアクセスすることができます。

変数はメンバとローカルに関わらず、次のように定義します。

(修飾子) 型 変数名;

型と変数名は定義時の必須項目で、修飾子はアクセスレベルや定数化等の設定をすることができます。

また変数は、宣言と同時に初期化することもでき、1つの型で複数の変数を定義するとこもできます。

(修飾子) 型 変数名 = 初期値;

(修飾子) 型 変数名, 変数名,  ・・・;

メンバ変数の場合、String型ならばnullchar型ならば空文字int型ならば0のように暗黙で初期化が行なわれますが、明示的に初期化しておくのが無難でしょう。

・サンプルコード

問題 3-1-3

int型とString型のメンバ変数を定義した「TestClass」クラスを作成してみよう。
(それぞれは定義と同時に初期化も行う事とする。)

1.4. メソッドの定義

メソッドとは、クラスを作成する時にそのクラスの様々な機能をまとめるしくみのことです。

テレビ」というモノ(クラス)で例えると、「」や「画面の大きさ」がそのモノの性質となり、「画面を映す」や「チャンネルを変える」がそのモノの機能となり、メソッドに定義します。

メソッドは、次のようにクラス内にブロック({ })で囲んで記述し、機能をまとめます。

修飾子に「static」を指定すると静的メソッドとなり、また「public」や「private」を指定することでそのメソッドのアクセスレベルを設定することもできます。

修飾子に関しては、後の節で詳しく説明するので、ここでは設定できるということだけ覚えておいて下さい。

戻り値」は、そのメソッドを呼び出して実行した時に呼び出し元に返される値のことをいい、その値の型を1つだけ定義することができます。戻り値を必要としない場合、「void」を定義します。

またメソッドは、実行するために必要な情報を「引数」として渡すことができ、引数の型と引数名を複数定義できます。なにも定義しない場合は、単に()を記述します。

戻り値と引数に関しても、後の節で詳しく説明するので、ここでは定義の方法だけ覚えておいて下さい。

問題 3-1-4

privateという修飾子が指定された引数と戻り値を持たない「testMethod」を定義してみよう。
(処理の内容を問わず、メソッドの定義のみで良い。)

1.5. 引数と戻り値

メソッドは、呼び出す際に値を引き渡し、その値に応じた動的処理を実行させることができます。その引き渡す値を引数といい、また呼び出し元にその処理結果等の値を返すこともできます。その返される値を戻り値といいます。

それでは、それぞれ実際にサンプルコードを用いて学習しましょう。

サンプル1(引数の学習)

Sample1クラスshowNumメソッドは、int型の値を1つ渡すように定義したものです。このメソッドの( )にある「int n」が引数です。

引数nは、このメソッド内でのみ使用できる変数となっていて、メソッド内ではnを処理に使用することができます。またメソッドは、showNumAndStringメソッドのように2つ以上の引数を定義することもできます。その場合は、引数をカンマ( , )で区切って定義します。この複数の引数を、引数リストと呼ぶこともあります。

また引数は、メソッドで定義されている引数(変数)を仮引数といい、呼び出し元から渡される引数(値)を実引数といいます。メソッドに引数を指定しない場合、「show()」のように引数の部分に何も指定しないでおきましょう。

では次に、Sample1クラス実行するためのExecSample1クラスを見てみましょう。

引数の定義されたメソッドを実行するには、そのメソッドで定義された型と引数の数に注意して記述します。

showNumメソッドを呼び出すためにはint型の実引数を1つ、showNumAndStringメソッドを呼び出すためにはint型の実引数を1つとString型の実引数を1つ、その順番に定義するように注意します。

またshowNumAndStringのように実引数に変数を定義することもできます。

引数の定義されたメソッドの特徴として、showNumメソッドの呼び出しのように違う実引数を渡すことにより、違う実行結果が得られるということを覚えておいて下さい。つまり、引数として渡された値によって柔軟な処理を行うことができるというわけです。

サンプル2(戻り値の学習)

メソッドは、呼び出し元に特定の情報を返すことができます。その返される情報を戻り値といいます。

戻り値は、複数指定できる引数とは違って1つだけ呼び出し元に情報を返すことができます。戻り値を返すには、Sample2クラスのcalcNumメソッドのようにメソッド名の前に返したい戻り値の型を定義し、returnという命令文を使って実際に値を呼び出し元に返す処理をします。

Sample2クラスを実行するためのExecSample2クラスでは、mainメソッドでcalcNumに「10」を引き渡し、2倍して返されたint型の値をretNumというint型の変数に代入して表示しています。

なお、戻り値は必ずしも呼び出し元で使用しなくてもかまいません。単に「smpl2.calcNum(10);」とだけ記述することもできます。また、戻り値を必要としないメソッドを定義するには、メソッド名の前に「void」という型を指定します。その場合のreturn文は記述してもしなくてもかまいません。

問題 3-1-5

int型の戻り値を持ち、int型の引数を3つ受け取って、計算して返す「calculate」メソッドを作成してみよう。 (計算の方法は問いません)

1.6. スコープとアクセス制御について(1)

Javaは、クラスのメンバ(フィールド・メソッド)に修飾子をつけ、スコープ範囲を制限したり、アクセスを制御したりすることでそのクラスの独立性や安全性を高めることができます(カプセル化)

クラスのフィールドを直接操作して、不正な値が代入されるとプログラムの動作がおかしくなってしまう場合があります。このような場合は、そのフィールドへの直接的なアクセスを禁止し、そのフィールドに正常な値のみ代入を行なうアクセス可能なメソッドを用意するわけです。

上記のように記述しないとコンパイルエラーになったりはしないですが、安全なプログラム開発を行なうためには、ぜひ実装しておくべきでしょう。

では実際に、使用できる修飾子を以下に説明していきましょう。

(1) public

publicを指定すると、全てのクラスからアクセスすることができます。

(2) private

privateを指定すると、自クラスからのみアクセスすることができます。

(3) protected

protectedを指定すると、同じパッケージ、またはそのサブクラスからしかアクセスできません。

・コーディングサンプル

    // どこからでもアクセス可能な変数です。
    public String str1;

    // 同クラス内からのみアクセス可能な変数です。
    private String str2;

    // 同パッケージか、サブクラスのみアクセス可能な変数です。
    protected String str3;

    // どこからでもアクセス可能なメソッドです。
    public void method1() {

    }

    // 同クラス内からのみアクセス可能なメソッドです。
    private void method2() {

    }

    // 同パッケージか、サブクラスのみアクセス可能なメソッドです。
    protected void method3() {

    }

また、「final」という修飾子もありますが、詳しくは「2.6. finalキーワード」を参照して下さい。

問題 3-1-6

他クラスからアクセス不可能な定数を持ち、その定数の値を返すどこからでもアクセス可能なメソッドを持つクラスを作成してみよう。

1.7. スコープとアクセス制御について(2)

Javaには、前節で説明した修飾子とは別に「static」という修飾子があります。

staticは、publicprivateと同様にメソッドと変数につけることのできる修飾子です。staticをつけたメソッドを「静的メソッド」、変数を「静的変数」といいます。

static修飾子の特徴として、staticをつけたメンバはクラスをインスタンスすることなく、呼び出したり、参照したりすることができます。具体的にソースで見てみましょう。

class Sample1 {

    //static修飾子をつけたメソッド
    static void show(){
        System.out.println("staticメソッド");
    }
}
class ShowSample1 {
    public static void main(String[] args){

        //staticなメソッドを実行します。
        //インスタンス化せずに呼び出しています。
        Sample1.show ();
    }
}

上記の様に、メソッドは「クラス名.メソッド名();」として呼び出し、変数は「クラス名.変数名;」として参照することができるのです。もちろん、今まで学んできたようにインスタンス化して呼び出したり、参照したりすることもできます。

また、staticメソッドは、「静的メソッドから自分のクラス内の静的ではないメソッドを実行できない。」という注意点があります。下のSample2クラスのようにstaticをつけたメソッドから自分のクラスのstaticをつけていないメソッドを呼び出すとコンパイルエラーとなります。同じく、静的でない変数も参照することはできません。

class Sample2 {

    //staticメソッド
    static void show1(){
        System.out.println("Staticメソッド");
        //staticではないメソッドを実行(コンパイルエラー)
        show2();
    }

    //staticではないメソッド
    void show2(){
        System.out.println("Staticではないメソッド");
    }
}

また、static修飾子のもう1つの特徴として、通常のメンバは個々のインスタンス毎に別々に保持していますが、static 宣言されたメンバについてはいくつインスタンスが生成されても、 クラスがただ一つだけ保持しています。静的メソッド、静的変数はそのクラス内で1つという位置付けで、そのクラスのオブジェクトがいくつ生成されても、生成したオブジェクト毎にメソッドや変数が割り当てられることはありません。具体的に図説すると下記の通りです。

【静的メンバ】 クラスに対して割り当てられます。

【静的でないメンバ】 オブジェクトに対して割り当てられます。

問題 3-1-7

staticな変数を持つStaticClassと、それを使用するExecStaticClassstaticの特性を利用して作成してみよう。

1.8. メソッドの利用法(同クラス、別クラス)

クラスに定義されたメソッドは、同じクラスと別クラスで利用や呼び出し方法が異なります。

1.8.1. 同じクラスのメソッド呼び出し

同クラス内に定義されたメソッドを呼び出す場合、呼び出したいメソッド名のみを記述することでそのメソッドを利用することが可能です。また、自分のクラスを強調して、「this.」という指定をすることもできます。下記、サンプルコード1では、mainメソッドで自クラスのmethodAをメソッド名のみで呼び出し、methodBを「this.」で指定して呼び出しています。

・サンプルコード1(同クラス内のメソッド利用)

class Sample1 {

    // mainメソッド
    public static void main(String[] args) {
        Sample1 s1 = new Sample1();
        s1.method0();
    }

    public void method0()
    {
        // メソッド名だけを指定して呼び出しています。
        methodA();

        // メソッド名にthis.を指定して呼び出しています。
        this.methodB();

    }

    public void methodA() {
        System.out.println("MethodA");
    }

    public void methodB() {
        System.out.println("MethodB");
    }
}

1.8.2. 別のクラスのメソッド呼び出し

別のクラスのメソッドを呼び出す場合、呼び出したいメソッドが定義されているクラスをインスタンス化し、「インスタンス変数名.メソッド名();」として利用することが可能です。下記、サンプルコード2では、Sample2クラスのmainメソッドでSample3クラスをインスタンス化し、methodCメソッドを呼び出しています。

・サンプルコード2(別クラスのメソッド利用)

class Sample2 {

    public static void main(String[] args) {

        // Sample3クラスをインスタンス化します。
        Sample3 smpl3 = new Sample3 ();

        // 「インスタンス変数.メソッド名」とし、methodCを呼び出しています。
        smpl3.methodC();

    }

}

class Sample3 {

    static void methodC() {
        System.out.println("MethodC");
    }

}

問題 3-1-8

自分のクラスに定義されたメソッドと別のクラス(OtherClass)に定義されたメソッドを利用する「MethodTest」クラスを作成してみよう。メソッドの処理内容は問いません。