【オブジェクト指向】Java入門〜中編〜

前書き

前回の記事。Javaの基本文法について学びました。
melheaven.hatenadiary.jp

それでは今回はオブジェクト指向について学んでいきます。

オブジェクト指向

オブジェクト指向とはソフトウェアを開発する際に部品化する考え方です。オブジェクト指向を意識したプログラムを書くことによって、柔軟性・保守性・再利用性が向上します。チームメンバーが把握しやすいプログラムを書くことが効率をあげるのです。

オブジェクト指向型の開発では、設計図の中の物や人物を部品と捉え、「クラス」として定義していきます。そして彼らの状態・情報を「フィールド」、彼らの振る舞いを「メソッド」として定義します。

オブジェクト指向の機能について3つほど列挙します。

  • カプセル化(属性や操作など、他クラスからの利用を禁止する)
  • 継承(過去に作った部品を流用)ex) 動物クラスの特性を人間クラスに応用させる
  • 多態性(細かい点には目を瞑り、共通項を見つけて「同じ部品」とみなす)

オブジェクト指向の流れ

  1. クラスを定義する(設計書作り)
  2. クラスに基づいてインスタンスを生成(設計書通りに生産する)

ここで設計書(クラス)通りに生産して、仮想世界上で活躍する実体をインスタンスとします。1つのクラスから複数のインスタンスを生成する事が通常です。

クラスの定義とインスタンスの生成

以下のコードは"Horse.java"に記載されています。
競馬レースをクラスとして、それぞれのレースには騎手・オッズ・順位・馬がフィールドとして割り当てられています。メソッドでは実際に「馬の表示」「騎手の表示」としました。

// 競馬レースクラス
public class Horse  {

    //    フィールドはクラス全域で有効
    String horse = "ディープインパクト";
    String jockey = "武豊";
    double odds = 1.1;
    int rank = 0;

    // メソッド
    public void horseDisplay() {
        System.out.println("<馬> : 馬は" + horse + "です。");
    }

    public void jockeyDisplay() {
        System.out.println("<騎手> : 騎手は" + jockey + "です。");
    }
}

mainクラスにてインスタンスを以下のように定義します。ここでHorse型として、horseRace1というインスタンスが定義されました。

Horse horseRace1 = new Horse();
horseRace1.horseDisplay();
horseRace1.jockeyDisplay();

<馬> : 馬はディープインパクトです。
<騎手> : 騎手は武豊です。

コンストラク

コンストラクタとは「newで呼び出したインスタンスに初期状態にて行われる処理」です。
以下のコードでは2つのコンストラクタが存在します。1. 引数なしコンストラクタと2. 引数ありコンストラクタです。
コンストラクタは基本的には最低1つでも良いのですが、今回はthisの説明の為に2つ用意しました。

インスタンスを動作させてみます。

public class Horse  {

    //    フィールドはクラス全域で有効
    String horse;
    String jockey;
    double odds;
    int rank;

     //    コンストラクタ
     //    引数なしコンストラクタ
    Horse() {
        System.out.println("<---------引数なしコンストラクタ動作-------->");
        this.horse = "未登録";
        this.jockey = "未登録";
        this.place = "未登録";
        this.odds = 0;
        this.rank = 0;
    }

     //    コンストラクタ
     //    引数ありコンストラクタ
     public Horse(String jockey, String horse, double odds, String place) {
        //        コンストラクタ内でもコンストラクタの呼び出しは具体的な処理よりも前に(thisはコンストラクタの先頭に)
        //        深い処理→浅い処理の実行順(thisはコンストラクタの呼び出し)
        this();
        System.out.println("<---------引数ありコンストラクタ動作-------->");
        this.horse = horse;
        this.jockey = jockey;
        this.odds = odds;
        this.place = place;
        super.name = "競馬";
        super.name();
    }
}
Horse horseRace1 = new Horse("和田竜", "ディープポンド", 3.4,"阪神競馬場");

<---------引数なしコンストラクタ動作-------->
<---------引数ありコンストラクタ動作-------->

ここで動作する順番は”引数なしコンストラクタ”→”引数ありコンストラクタ”の順でした。
引数ありコンストラクタの1行目にthis()にて、Horse()を呼び出しています。thisを追加するとコンストラクタを呼び出しすることができ、各フィールドに一瞬、"未登録"というデータが格納されます。

コンストラクタには条件があります。

  1. メソッド名がクラス名と完全に等しい
  2. 戻り値が記述されていない。

カプセル化

カプセル化とは、フィールドの読み書きやメソッドの呼び出しを制限する機能です。「誰がどのメソッドを呼び出せるか」など権限を与えて、外部のクラスから不要な呼び出しを制限することで、悪意やヒューマンエラーによるシステムバグを回避します。

public class Horse {

    //    フィールドはクラス全域で有効
    private String horse;
    private String jockey;
    private double odds;
    private int rank;

    // コンストラクタは省略

    // 以下メソッド
    public void interview(int firstPrice)  {
        result();
        if (this.rank < 1) {
                System.out.println("<結果> : 順位は" + (this.rank + 1) + "です。勝ちました!" + horse + "に騎乗した" + jockey + "さんのインタビューです!");
                System.out.println("<配当> : 配当は" + price(firstPrice) + "円です。");
        } else {
                System.out.println("<結果> : 順位は" + this.rank + "です。負けました。配当もインタビューもありません。");
        }
    }

    private void result() {
        Random rand = new Random();
        this.rank = rand.nextInt(2);
    }

    private double price(int firstPrice) {
        return odds * firstPrice;
    }
}
Horse horseRace2 = new Horse("福永祐一", "ワールドプレミア", 1.6,"阪神競馬場");
horseRace2.interview(price);

<---------引数なしコンストラクタ動作-------->
<---------引数ありコンストラクタ動作-------->
<結果> : 順位は1です。勝ちました!ワールドプレミアに騎乗した福永祐一さんのインタビューです!
<配当> : 配当は1600.0円です。

ここではmainメソッドからHorseクラスのインスタンスを生成します。その後、interviewメソッドを呼び出しています。その為、interviewメソッドは外部クラスからの呼び出しがなされているので、アクセス制御レベルは"public"とします。

次にinterviewメソッド内で利用されているresultメソッドとpriceメソッドについては同一クラス内からの呼び出しとなっています。その為、外部のクラスが両メソッドを呼び出しする必要はないので、resultメソッドとpriceメソッドのアクセス制御レベルは"private"とします。

名前 アクセス許可範囲
private 自身のクラスのみ
package private(何も書かない) 自身と同じパッケージに属するクラス
protected サブクラス(継承した)と自身と同じクラス
public 全てのクラス