Javaプログラミング入門 9章 [クラス型の活用]

Java

こんにちは。ECF Techブログ
担当 Michiharu.Tです。

Javaプログラミング入門記事の第9章をお送りいたします。
第9章のテーマは「クラス型の活用」です。

本連載の初回および章立ての一覧については下記のリンクから確認できます。

Javaプログラミング入門 0章
0章 Javaプログラミングを始めよう こんにちは。ECF Techブログ 担当 Michiharu.Tです。 この記事はプログラミング言語のJavaを、実際に動かしながら学びたい人のための学習教材となっています。手を多く動かすこと、感覚を...

解説動画

2024/02/02 解説動画を掲載しました。

9-1 クラス同士の関係性

オブジェクト指向でプログラムの構成を考える場合、オブジェクト同士が互いにどのような関係性にあるかを考えます。

お店アプリを例にすると・・・

  • 商品クーポンを適用する。
  • 利用者ポイントカードを保有する。
  • 利用者最寄り店舗を登録する。

※太字はオブジェクトです。

などの事柄をどうプログラムで構成していくか。ということを考えることになります。そして、これら複数のオブジェクトの関係性をプログラムで表現することで、よりオブジェクト指向らしいプログラムとなります。

概要だけですとイメージしづらいですので、具体的なプログラムで確認します。本章ではお店アプリを題材に「利用者がポイントカードを保有する」というケースについて考えます。

9-1-1 クラス型のフィールド

まずは3つのクラスからなるプログラムをまとめて示します。

プログラム例(PointCard.java)

public class PointCard {
    int id;     //カード番号
    int point;  //残ポイント

    //コンストラクタ
    PointCard(int id, int point) {
        this.id = id;
        this.point = point;
    }

    //支払処理
    void payment( int price ){
        //金額の1%をポイントに加算
        point += price*0.01;
    }
}

プログラム例(User.java)

public class User {
    String name;    //名前
    PointCard card; //ポイントカード

    //コンストラクタ
    public User(String name) {
        this.name = name;
    }
}

プログラム例(Main.java)

public class Main {
    public static void main(String[] args) {
        User user = new User("タロウ");
        PointCard card = new PointCard(1234, 500);
        user.card = card;

        System.out.println(user.card.point);
        user.card.payment(1000);
        System.out.println(user.card.point);
    }
}

実行結果

500
510

プログラム量が一気に増えた印象ですが、使われているのはこれまで学習した内容がほとんどです。新しい要素は次の2つです。

  • Userクラスにクラス型のフィールド(PointCard card;)が定義されている。
  • メインクラス内のuser.card.pointuser.card.payment(1000)という記述。

それでは、各クラスの概要を説明します。

PointCardクラス
PointCardクラスは次の2つのフィールドを持っています。

  • カード番号を表すid
  • 残ポイントを表すpoint

コンストラクタは引数の値を各フィールドに設定する処理となっています。

また、paymentというメソッドを持っています。paymentメソッドは金額(price)を引数にとり、金額の1%をpointフィールドに加算する処理を行います。

Userクラス
Userクラスは次の2つのフィールドを持っています。

  • 名前を表すname
  • ポイントカードを表すcard

注目すべきは、ポイントカードを表すcardフィールドがPointCard型、つまりクラス型になっている点です。どのような動作になるかは、mainメソッドの処理内容を追いかけながら説明します。

コンストラクタは引数の値をnameフィールドに設定する処理となっています。

それではmainメソッドの動作を確認します。下図に基づいて説明します。

インスタンスの関連

図はメインクラスの5行目までが実行されたときの処理です。

3行目User user = new User("タロウ");
Userインスタンスを生成し、変数userにそのアドレスを保持しています。コンストラクタを使って、nameフィールドにタロウを設定しています。

4行目PointCard card = new PointCard(1234, 500);
PointCardインスタンスを生成し、変数cardにそのアドレスを保持しています。コンストラクタを使って、idフィールドに1234、pointフィールドに500を設定しています。

5行目user.card = card
Userインスタンスの持つフィールドcardに変数cardの値を代入する操作です。ここでuser.cardに代入されるのは変数cardに入っているアドレスです。したがって、user.cardも変数cardと同じPointCardインスタンスを指すようになります。図のオレンジ色の矢印が該当のイメージです。

この図の状態で、7行目以降の処理が行われます。7行目のuser.card.pointは次の図のように.を、矢印と見なすといいでしょう。

インスタンスの関連

文章で表現する場合は、下のように.を「」と読むイメージです。

変数userの指すインスタンス
cardフィールドが指すインスタンス
pointフィールド

つまり、PointCardインスタンスのpointフィールドに入っている値を示しています。よって、画面には500が表示されます。

8行目も同様です。user.card.payment(1000)は、

変数userの指すインスタンス
cardフィールドが指すインスタンス
paymentメソッド

を呼び出す処理。となります。引数には1000が渡されていますので、その1%である10がpointフィールドに加算されることになります。

9行目で再度user.card.pointを表示すると、510が表示されます。

9-1-2 nullの活用

UserクラスにPointCard型のフィールドを定義することで、「ユーザーがポイントカードを保有する」という関係を表現することができました。このフィールドにnullを代入することで、ユーザーがポイントカードを持っていない状態を表現することも可能です。

プログラム例として、9-1-1のUserクラスの修正版を示します。

プログラム(User.java)

public class User {
    String name;    //名前
    PointCard card; //ポイントカード

    public User(String name) {
        this.name = name;
    }

    void display() {
        System.out.println("名前:"+name);
        if (card == null) {
            System.out.println("カードを所持していません。");
        } else {
            System.out.println("カード情報:");
            System.out.println("ID:" + card.id 
                + " 残ポイント:" + card.point);
        }
    }
}

新たにdisplayメソッドを作成しています。11行目でcardフィールドがnullかどうかを判断する条件式を使い、表示方法を分けています。

次にメインクラスのプログラムを示します。

プログラム(Main.java)

public class Main {
    public static void main(String[] args) {
        User taro = new User("タロウ");
        PointCard card = new PointCard(1234, 500);
        taro.card = card;
        User hanako = new User("ハナコ");

        taro.display();
        hanako.display();
    }
}

実行結果

名前:タロウ
カード情報:
ID:1234 残ポイント:500
名前:ハナコ
カードを所持していません。

各処理を解説します。

  • 3行目:Userインスタンスを生成し、変数taroに代入
  • 4行目:PointCardインスタンスを生成し、変数cardに代入
  • 5行目:taroが指すインスタンスのcardフィールドに変数cardを代入
    ※変数taroとcardが指すインスタンス同士が関連をもつ
  • 6行目:Userインスタンスを生成し、変数hanakoに代入

6行目の処理が完了した時点で、各インスタンスは次のようになっています。

9-1-2図

変数hanakoが指すインスタンスのcardフィールドは何も指し示していないnullの状態です。

8行目で変数taroが指すインスタンスのdisplayメソッドを呼び出しています。同インスタンスはcardフィールドがPointCardインスタンスを指している状態なので、User.javaの11行目card == nullfalseとなり、elseブロックの処理を行います。よって、カードの詳細が表示されます。

9行目の変数hanakoが指すインスタンスのdisplayメソッド呼び出しでは、同インスタンスのcardフィールドがnullなので、card == nulltrueとなり、「カードを所持していません。」のメッセージが表示されます。

フィールドは通常の変数と異なり、インスタンス生成時に代入処理を行わなくても初期値が決定します。初期値は型によって、次のように設定される値が決まります。

フィールドの型 初期値
整数型 0
浮動小数点数型 0.0
boolean型 false
char型 ''
参照型 null

9-2 クラス型の引数

9-1では、次のようにUserインスタンスを一旦生成し、あとからPointCardインスタンスを代入する処理を行っていました。

User taro = new User("タロウ");
PointCard card = new PointCard(1234, 500);
taro.card = card;

ここでは、クラス型を引数として活用し、Userクラスのコンストラクタを改良する例をご紹介します。

プログラム例を示します。

プログラム(User.java)

public class User {
    String name;    //名前
    PointCard card; //ポイントカード

    public User(String name, PointCard card) {
        this.name = name;
        this.card = card;
    }

    void display() {
        System.out.println("名前:"+name);
        if (card == null) {
            System.out.println("カードを所持していません。");
        } else {
            System.out.println("カード情報:");
            System.out.println("ID:" + card.id 
                + " 残ポイント:" + card.point);
        }
    }
}

コンストラクタを修正し、PointCard型の引数を受け取れるようにしています。続けてメインクラスを示します。

プログラム(Main.java)

public class Main {
    public static void main(String[] args) {
        PointCard card = new PointCard(1234, 500);
        User taro = new User("タロウ",card);

        taro.display();
    }
}

実行結果

名前:タロウ
カード情報:
ID:1234 残ポイント:500

3行目でPointCardインスタンスを先に生成し、変数cardに代入。次にその変数cardをUserインスタンス生成の際に、コンストラクタに引数として渡しています。この時渡されるのは変数cardに代入されているアドレスです。したがって、コンストラクタ経由で変数userが指すインスタンスのcardフィールドにアドレスが代入されます。

これによりUserインスタンスのcardフィールドが、PointCardインスタンスを指し示すようになります。

タイトルとURLをコピーしました