インスタンスメソッド

クラスの内部に含まれる個々のデータを表すのがフィールドでした。 クラスは製品の設計図に例えられますが、一般的に製品は何らかの機能を持っているものです。 従って、クラスの内部にも、機能を記述する方法がほしいところです。 メソッド(method)を使えばそれを実現することができます。 メソッドについては、第9章で詳しく学習しましたが、それは宣言するときにstaticの付くクラスメソッドでした。 ここでは、staticの付かないインスタンスメソッドについて学習していきます。

インスタンスメソッドを宣言する

インスタンス変数がインスタンスの中に含まれるフィールドであるように、インスタンスメソッドはインスタンスの中に含まれるメソッドと言えます。

尚、フィールドやメソッドをまとめてメンバ(member)と呼びます。

インスタンスメソッドの宣言は次のようになります。 先頭にstaticが付いていないことを除けば、クラスメソッドの宣言と同じです。

構文 : メソッド宣言(インスタンスメソッド)
    戻り値の型  メソッド名(引数リスト){
        文1
        文2
        ...
        return 式;
    }

では、Robotクラスで、状態を表示するインスタンスメソッドを宣言してみましょう。

class Robot {
    String name;    //名前
    int battery;    //バッテリー残量
    
    /*---- 状態を表示する ----*/
    void showStatus(){
        System.out.println("バッテリー残量: " + battery);
    }
}
表 10-2 : showStatusメソッド
戻り値の型 メソッド名 引数リスト
void showStatus 空白

メソッドの仮引数は空白でも良かったのでしたね。 戻り値の型がvoidというのは、戻り値を返さないという意味でした。

ところで、showStatusメソッドの内部では、robot1.batteryのようにインスタンスを指定することなく、単にbatteryと書くことでフィールドにアクセスしています。 これができるのは、batteryがインスタンス自身の持っているフィールドだからです。

インスタンス自身のフィールドは、フィールド名だけでアクセスできる。

インスタンスメソッドを呼び出す

インスタンスメソッドを呼び出すには、次のように記述します。

構文 : インスタンスメソッドの呼び出し
クラス型変数名.メソッド名(引数リスト)

フィールドへのアクセスと同じように、クラス型変数名とメンバアクセス演算子(.)を使って、インスタンスを指定して呼び出すのです。

次のように、Robotクラスのインスタンスが生成されているとしましょう。

        Robot robot1 = new Robot();

このとき、robot1が参照するインスタンスのshowStatusメソッドを呼び出すには、次のように記述します。

        robot1.showStatus();

Robotクラスのメソッドを使ってみる

次のRobotTest02は、showStatusメソッドを使ってRobotTest01を書き換えたものです。

RobotTest02.java
//ロボットクラス【第2版】
class Robot {
    String name;    //名前
    int battery;    //バッテリー残量
    
    /*---- 状態を表示する ----*/
    void showStatus(){
        System.out.println("バッテリー残量: " + battery);
    }
}

//ロボットクラス【第2版】のテスト用クラス
class RobotTest02 {
    public static void main(String[] args) {
        Robot robot1 = new Robot();
        robot1.name = "ロボ太郎";
        robot1.battery = 100;
        
        Robot robot2 = new Robot();
        robot2.name = "ロボ子";
        robot2.battery = 90;
        
        System.out.println("名前: " + robot1.name);
        robot1.showStatus();
        System.out.println();
        System.out.println("名前: " + robot2.name);
        robot2.showStatus();
    }
}

実行結果はRobotTest01と同じです。

RobotTest02の実行結果
名前: ロボ太郎
バッテリー残量: 100

名前: ロボ子
バッテリー残量: 90

mainメソッドから robot1.showStatus(); という形でメソッドが呼び出されると、showStatusメソッドの先頭に処理が移ります。 System.out.println("バッテリー残量: " + battery); が実行されると、すぐにメソッドの最後の行に達し、メソッドは終了して呼び出し元に処理が戻ります。 この後は System.out.println(); の実行により改行されます。

図 10-7 : showStatusメソッドの呼び出し

showStatusメソッドはインスタンスメソッドですから、それはrobot1, robot2が参照する各インスタンスの中に含まれています。 その様子を示すのが図 10-8です。

図 10-8 : インスタンスメソッドはインスタンスの中に含まれるメソッド

メソッドでフィールドの値を変更する

Robotクラスに、x軸方向に歩くメドッドを追加してみましょう。 メソッドを宣言する前に、Robotクラスに現在位置(x座標)を表すフィールドを追加しておきます。 このx座標を増減することで、ロボットが歩くことを表現するのです。

class Robot {
    String name;    //名前
    int battery;    //バッテリー残量
    int x;    //x座標
    ...
}

x軸方向に歩くメソッドでは、少し複雑な処理をさせてみましょう。 具体的な動作は次のようなものとします。

  • x軸方向の移動量を引数として受け取り、正負のいずれの方向にも歩くことができる。
  • 移動距離(移動量の絶対値)と同じだけのバッテリーを消費する。 例えば、x軸方向に5だけ歩くならばバッテリーを5だけ消費し、-7だけ歩くなら7だけ消費する。
  • バッテリー残量が十分にある場合は、実際に移動して、trueを戻り値として返す。 しかし、バッテリー残量が不足している場合は、移動せず、falseを戻り値として返す。

では、実際にx軸方向に歩くメソッドを宣言してみましょう。

    boolean walkX(int dx){
        int d = dx >= 0 ?  dx : -dx;    //dxの絶対値をdに代入しておく。
        if(d <= battery){
            x += dx;
            battery -= d;
            return true;
        }else{
            return false;
        }
    }
表 10-3 : walkXメソッド
戻り値の型 メソッド名 引数リスト
boolean walkX int dx

仮引数のdxは移動量を表します。 例えば、x軸の正の方向に4だけ移動するならdxの値は4で、負の方向に9だけ移動するならdxの値は-9ということになります。

では、メソッド本体の処理を見ていきましょう。 まず、dxの絶対値(移動距離)を変数dに代入します。 if文で d <= battery が真のときは、移動量の分だけxを変化させ、とbatteryは移動量の絶対値の分だけ減らします。 その後、return true; が実行されてメソッドは終了し、戻り値のtrueを呼び出し元に返します。 一方、偽のときは return false; が実行されてメソッドは終了し、falseを呼び出し元に返します。

以上から分かるように、戻り値は実際に移動できたかどうかを表します。

ついでに、showStatusメソッドをxフィールドの値も表示するように変更しておきましょう。

    void showStatus(){
        System.out.println("現在のx座標: " + x);
        System.out.println("バッテリー残量: " + battery);
    }

メソッドからインスタンス自身のメソッドを呼び出す

更にもう一つ、名前と状態をまとめて表示するメソッドを宣言してみましょう。

    void show(){
        System.out.println("名前: " + name);
        showStatus();
    }
表 10-4 : showメソッド
戻り値の型 メソッド名 引数リスト
void show 空白

showメソッドの特徴は、その内部でshowStatusメソッドを呼び出していることです。 やはり、 robot1.showStatus() のような形では呼び出さず、単に showStatus() と書くことで呼び出しています。 フィールドのときと同様に、インスタンス自身のメソッドは、インスタンスを指定することなく、メソッド名だけで呼び出すことができるのです。

インスタンス自身のメソッドは、メソッド名だけで呼び出すことができる。

ロボットを歩き回らせてみる

RobotTest03はwalkXメソッドでロボットを歩き回らせ、その都度状態を表示するプログラムです。

RobotTest03.java
//ロボットクラス【第3版】
class Robot {
    String name;    //名前
    int battery;    //バッテリー残量
    int x;    //x座標
    
    /*---- x軸方向に歩く ----*/
    boolean walkX(int dx){
        int d = dx >= 0 ?  dx : -dx;    //dxの絶対値をdに代入しておく。
        if(d <= battery){
            x += dx;
            battery -= d;
            return true;
        }else{
            return false;
        }
    }
    
    /*---- 状態を表示する ----*/
    void showStatus(){
        System.out.println("現在のx座標: " + x);
        System.out.println("バッテリー残量: " + battery);
    }
    
    /*---- 名前と状態を表示する ----*/
    void show(){
        System.out.println("名前: " + name);
        showStatus();
    }
}

//ロボットクラス【第3版】のテスト用クラス
class RobotTest03 {
    public static void main(String[] args) {
        Robot robot1 = new Robot();
        robot1.name = "ロボ太郎";
        robot1.battery = 100;
        
        robot1.show();    System.out.println();
        System.out.println(robot1.name + " が歩き回ります。");    System.out.println();
        int[] dxes = {40, -25, 50, 16};
        for(int dx : dxes){
            if(! robot1.walkX(dx)){
                System.out.println(robot1.name + " はバッテリー不足で歩けません。");
            }
            robot1.showStatus();
        }
    }
}
RobotTest03の実行結果
名前: ロボ太郎
現在のx座標: 0
バッテリー残量: 100

ロボ太郎 が歩き回ります。

現在のx座標: 40
バッテリー残量: 60
現在のx座標: 15
バッテリー残量: 35
ロボ太郎 はバッテリー不足で歩けません。
現在のx座標: 15
バッテリー残量: 35
現在のx座標: 31
バッテリー残量: 19

プログラム中ではrobot1.xの値は設定されていませんが、int型の既定値である0で初期化されています。

さて、次の部分に注目してください。

        int[] dxes = {40, -25, 50, 16};
        for(int dx : dxes){
            if(! robot1.walkX(dx)){
                System.out.println(robot1.name + " はバッテリー不足で歩けません。");
            }
            robot1.showStatus();
        }

RobotTest03では、walkXメソッドを4回呼び出します。 4回分の移動量は配列dxesの要素として与えられています。 つまり、1回目はx軸の正の方向に40、2回目は負の方向に25、...というように歩くことになります。 4回の繰り返しは、拡張for文によって行われ、各回の移動量は変数dxに格納されることになります。

if文の条件では、walkXメソッドが呼び出されています。 walkXメソッドの戻り値は、そのまま robot1.walkX(dx) という式の値となります。 robot1.walkX(dx) の値がfalseのとき、即ち歩けなかったとき、 ! robot1.walkX(dx) の値がtrueとなって、「ロボ太郎 はバッテリー不足で歩けません。」が表示されます。

尚、戻り値を返すメソッドであっても、呼び出しだけが目的で、戻り値を利用する必要が無い場合もあり得ます。 そんなときは、次のようにメソッドを呼び出すだけで戻り値を利用しない書き方もできます。

        robot1.walkX(8);

図 10-9は、拡張for文でwalkXメソッドを繰り返し呼び出す様子を示しています。

図 10-9 : walkメソッドを繰り返し呼び出す