1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オブジェクト指向って何?RPGで理解する超入門 (コンストラクタ)

Last updated at Posted at 2025-12-16

title_banner_v2.png

はじめに

こんにちは。このシリーズでは、RPGゲームを作りながらJavaのオブジェクト指向を学んでいます。

前回までのおさらい:

第3回では、フィールドとメソッド、staticキーワード、thisキーワードについて学びました。
そして「冒険者ギルド」を実装し、共通情報と個別情報の管理方法を理解しましたね。

今回のテーマは「コンストラクタ」です。

実は、初学者の方から最もよく受ける質問の一つが、
「なぜnewの後ろに()があるんですか?」
「フィールドに値を設定し忘れて、エラーが出ます...」

という内容です。

これらの問題を解決するのが、今回学ぶ「コンストラクタ」です。

この記事で学ぶこと:

  • コンストラクタとは何か
  • コンストラクタの書き方と使い方
  • コンストラクタのオーバーロード
  • デフォルトコンストラクタの仕組み
  • this()によるコンストラクタチェイン
  • 初期化の順序

所要時間: 約15〜20分

今回のクエスト:職業システムを実装しよう

job_selection_screen.png

今回は、RPGの「職業システム」を実装します。

冒険者を作成するとき、以下の職業から選べるようにします:

  • 戦士(Warrior): HP高め、攻撃力高め
  • 魔法使い(Mage): MP高め、魔力高め
  • 僧侶(Priest): 回復力高め、バランス型

職業によって、初期ステータスが異なります。
これを実装するには、インスタンス作成時に初期値を設定する仕組みが必要です。

それが「コンストラクタ」です!

コンストラクタとは?

定義

コンストラクタ(Constructor)は、インスタンスを生成するときに自動的に呼ばれる特殊なメソッドです。

主な役割は、インスタンスの初期化です。

これまでの問題点

第1回で、こんなコードを書きました:

Player hero = new Player();
hero.name = "勇者";
hero.hp = 100;
hero.maxHp = 100;
hero.attack = 15;

問題点:

  • フィールドへの値設定を忘れやすい
  • 初期化が漏れると、バグの原因になる
  • 毎回同じような初期化コードを書く必要がある

もっと良い方法があります:

// コンストラクタを使った作成
Player hero = new Player("勇者", 100, 15);

たった1行で、名前、HP、攻撃力を設定できます!

コンストラクタの仕組み

constructor_mechanism(1).png

new Player()の裏側で何が起きているのか?

Player hero = new Player("勇者", 100, 15);

このコードが実行されると、以下の順序で処理が進みます:

  1. メモリ確保: Playerインスタンス用のメモリ領域がヒープ上に確保される
  2. フィールドの初期化: フィールドがデフォルト値で初期化される
    • 数値型 → 0
    • boolean → false
    • 参照型 → null
  3. コンストラクタ実行: 引数で渡された値をフィールドに設定
  4. 参照を返す: 作成されたインスタンスへの参照がhero変数に代入される

ポイント:
コンストラクタは、インスタンス作成の「最後の仕上げ」をする特殊なメソッドです。

コンストラクタの書き方

基本構文

/**
 * プレイヤークラス
 */
public class Player {
    
    // フィールド
    String name;
    int hp;
    int maxHp;
    int attack;
    
    /**
     * コンストラクタ
     * 
     * @param name プレイヤーの名前
     * @param hp 初期HP
     * @param attack 攻撃力
     */
    public Player(String name, int hp, int attack) {
        // 引数の値をフィールドに設定
        this.name = name;
        this.hp = hp;
        this.maxHp = hp;  // 最大HPは初期HPと同じ
        this.attack = attack;
        
        System.out.println(name + "が冒険者として登録されました!");
    }
}

コンストラクタの特徴

  1. メソッド名がクラス名と同じ

    • public Player(...) ← クラス名と一致
  2. 戻り値の型を書かない

    • voidも不要
    • コンストラクタは必ずインスタンスを返す
  3. 引数を受け取れる

    • 普通のメソッドと同じように引数を定義できる
  4. 自動的に呼ばれる

    • newでインスタンスを作成すると自動実行される

thisキーワードの重要性(復習+詳細)

第3回でthisを学びましたが、コンストラクタでは特に重要です。

なぜthisが必要か?

public Player(String name, int hp, int attack) {
    this.name = name;  // this.name はフィールド、name は引数
    this.hp = hp;
    this.attack = attack;
}

引数名とフィールド名が同じ場合、thisがないと区別できません。

thisなしで書いたらどうなる?

public Player(String name, int hp, int attack) {
    name = name;      // ❌ 引数nameに引数nameを代入(意味なし)
    hp = hp;          // ❌ 引数hpに引数hpを代入(意味なし)
    attack = attack;  // ❌ 引数attackに引数attackを代入(意味なし)
}

フィールドには何も設定されません!
結果、フィールドはすべてデフォルト値(0やnull)のままです。

コンストラクタでは必ずthisを使いましょう。

職業システムの実装

それでは、実際に職業システムを実装してみましょう。

Playerクラス(職業対応版)

/**
 * プレイヤークラス(職業システム対応版)
 * 
 * 冒険者の情報を管理し、職業に応じた初期ステータスを設定します。
 */
public class Player {
    
    // ========================================
    // フィールド
    // ========================================
    
    /** プレイヤーの名前 */
    String name;
    
    /** 職業(Warrior, Mage, Priestなど) */
    String job;
    
    /** 現在のHP(体力) */
    int hp;
    
    /** 最大HP */
    int maxHp;
    
    /** 現在のMP(魔力) */
    int mp;
    
    /** 最大MP */
    int maxMp;
    
    /** 物理攻撃力 */
    int attack;
    
    /** 魔法攻撃力 */
    int magic;
    
    /** 防御力 */
    int defense;
    
    // ========================================
    // コンストラクタ
    // ========================================
    
    /**
     * 基本コンストラクタ
     * 名前と職業を指定して冒険者を作成します。
     * 職業に応じて初期ステータスが自動設定されます。
     * 
     * @param name プレイヤーの名前
     * @param job 職業("Warrior", "Mage", "Priest")
     */
    public Player(String name, String job) {
        this.name = name;
        this.job = job;
        
        // 職業に応じて初期ステータスを設定
        switch (job) {
            case "Warrior":
                // 戦士:高HP、高攻撃力、低MP
                this.maxHp = 150;
                this.maxMp = 20;
                this.attack = 20;
                this.magic = 5;
                this.defense = 15;
                break;
                
            case "Mage":
                // 魔法使い:低HP、高MP、高魔力
                this.maxHp = 80;
                this.maxMp = 100;
                this.attack = 8;
                this.magic = 25;
                this.defense = 5;
                break;
                
            case "Priest":
                // 僧侶:中HP、中MP、バランス型
                this.maxHp = 100;
                this.maxMp = 70;
                this.attack = 10;
                this.magic = 15;
                this.defense = 10;
                break;
                
            default:
                // デフォルト(職業未指定)
                this.maxHp = 100;
                this.maxMp = 50;
                this.attack = 10;
                this.magic = 10;
                this.defense = 10;
                System.out.println("⚠️ 不明な職業です。デフォルト値を設定しました。");
        }
        
        // 現在のHP/MPを最大値に設定
        this.hp = this.maxHp;
        this.mp = this.maxMp;
        
        // 作成完了メッセージ
        System.out.println("✅ " + name + "(" + job + ")が冒険者として登録されました!");
    }
    
    // ========================================
    // メソッド
    // ========================================
    
    /**
     * プレイヤーの詳細情報を表示します
     */
    public void showStatus() {
        System.out.println("========================================");
        System.out.println("名前: " + name);
        System.out.println("職業: " + job);
        System.out.println("----------------------------------------");
        System.out.println("HP: " + hp + " / " + maxHp);
        System.out.println("MP: " + mp + " / " + maxMp);
        System.out.println("----------------------------------------");
        System.out.println("攻撃力: " + attack);
        System.out.println("魔力: " + magic);
        System.out.println("防御力: " + defense);
        System.out.println("========================================");
    }
}

メインクラスで使ってみる

/**
 * ゲームのメインクラス(職業システムデモ)
 */
public class GameMain {
    
    public static void main(String[] args) {
        
        System.out.println("=== 冒険者ギルドへようこそ! ===\n");
        
        // ========================================
        // 職業を選んで冒険者を作成
        // ========================================
        
        // 戦士を作成
        Player warrior = new Player("アレン", "Warrior");
        warrior.showStatus();
        
        System.out.println(); // 空行
        
        // 魔法使いを作成
        Player mage = new Player("リナ", "Mage");
        mage.showStatus();
        
        System.out.println(); // 空行
        
        // 僧侶を作成
        Player priest = new Player("ヒカル", "Priest");
        priest.showStatus();
    }
}

実行結果

=== 冒険者ギルドへようこそ! ===

✅ アレン(Warrior)が冒険者として登録されました!
========================================
名前: アレン
職業: Warrior
----------------------------------------
HP: 150 / 150
MP: 20 / 20
----------------------------------------
攻撃力: 20
魔力: 5
防御力: 15
========================================

✅ リナ(Mage)が冒険者として登録されました!
========================================
名前: リナ
職業: Mage
----------------------------------------
HP: 80 / 80
MP: 100 / 100
----------------------------------------
攻撃力: 8
魔力: 25
防御力: 5
========================================

✅ ヒカル(Priest)が冒険者として登録されました!
========================================
名前: ヒカル
職業: Priest
----------------------------------------
HP: 100 / 100
MP: 70 / 70
----------------------------------------
攻撃力: 10
魔力: 15
防御力: 10
========================================

たった1行で、職業に応じた初期ステータスが自動設定されます!

コンストラクタのオーバーロード

constructor_overload_v2.png

第3回で「メソッドのオーバーロード」を学びましたが、
コンストラクタも同じようにオーバーロードできます。

なぜオーバーロードが必要?

冒険者を作成する方法は、状況によって異なります:

  1. シンプル作成: 名前だけ指定(職業はデフォルト)
  2. 職業選択: 名前と職業を指定
  3. 完全カスタマイズ: すべてのステータスを個別に指定

これらすべてに対応するため、複数のコンストラクタを用意します。

複数のコンストラクタを定義

/**
 * プレイヤークラス(コンストラクタオーバーロード版)
 */
public class Player {
    
    String name; // プレイヤーの名前
    String job;  // 職業
    int hp;      // HP
    int maxHp;   // 最大HP
    int mp;      // MP
    int maxMp;   // 最大MP
    int attack;  // 攻撃力
    int magic;   // 魔力
    int defense; // 防御力
    
    // ========================================
    // コンストラクタ1:名前のみ指定
    // ========================================
    
    /**
     * シンプルな冒険者作成
     * 職業は"Beginner"、ステータスはデフォルト値
     * 
     * @param name プレイヤーの名前
     */
    public Player(String name) {
        this.name = name;
        this.job = "Beginner";  // デフォルト職業
        
        // デフォルトステータス
        this.maxHp = 100;
        this.maxMp = 50;
        this.attack = 10;
        this.magic = 10;
        this.defense = 10;
        
        // 現在値を最大値に設定
        this.hp = this.maxHp;
        this.mp = this.maxMp;
        
        System.out.println("✅ " + name + "(初心者)が登録されました");
    }
    
    // ========================================
    // コンストラクタ2:名前と職業を指定
    // ========================================
    
    /**
     * 職業を選んで冒険者作成
     * 
     * @param name プレイヤーの名前
     * @param job 職業
     */
    public Player(String name, String job) {
        this.name = name;
        this.job = job;
        
        // 職業に応じた初期化(前述のコードと同じ)
        switch (job) {
            case "Warrior":
                this.maxHp = 150;
                this.maxMp = 20;
                this.attack = 20;
                this.magic = 5;
                this.defense = 15;
                break;
            case "Mage":
                this.maxHp = 80;
                this.maxMp = 100;
                this.attack = 8;
                this.magic = 25;
                this.defense = 5;
                break;
            case "Priest":
                this.maxHp = 100;
                this.maxMp = 70;
                this.attack = 10;
                this.magic = 15;
                this.defense = 10;
                break;
            default:
                this.maxHp = 100;
                this.maxMp = 50;
                this.attack = 10;
                this.magic = 10;
                this.defense = 10;
        }
        
        this.hp = this.maxHp;
        this.mp = this.maxMp;
        
        System.out.println("✅ " + name + "(" + job + ")が登録されました");
    }
    
    // ========================================
    // コンストラクタ3:全パラメータを指定
    // ========================================
    
    /**
     * 完全カスタマイズで冒険者作成
     * すべてのステータスを個別に指定できます
     * 
     * @param name プレイヤーの名前
     * @param job 職業
     * @param hp 初期HP
     * @param mp 初期MP
     * @param attack 攻撃力
     * @param magic 魔力
     * @param defense 防御力
     */
    public Player(String name, String job, int hp, int mp, int attack, int magic, int defense) {
        this.name = name;
        this.job = job;
        this.maxHp = hp;
        this.maxMp = mp;
        this.hp = hp;
        this.mp = mp;
        this.attack = attack;
        this.magic = magic;
        this.defense = defense;
        
        System.out.println("✅ " + name + "(カスタム" + job + ")が登録されました");
    }
    
    // showStatusメソッドは省略(前述と同じ)
    public void showStatus() {
        System.out.println("========================================");
        System.out.println("名前: " + name + " (" + job + ")");
        System.out.println("HP: " + hp + "/" + maxHp + " | MP: " + mp + "/" + maxMp);
        System.out.println("攻撃: " + attack + " | 魔力: " + magic + " | 防御: " + defense);
        System.out.println("========================================");
    }
}

オーバーロードの使い分け

/**
 * ゲームのメインクラス
 */
public class GameMain {
    public static void main(String[] args) {
        
        // パターン1:名前だけ指定(初心者として作成)
        Player player1 = new Player("太郎");
        player1.showStatus();
        
        System.out.println();
        
        // パターン2:名前と職業を指定
        Player player2 = new Player("花子", "Mage");
        player2.showStatus();
        
        System.out.println();
        
        // パターン3:全ステータスを個別指定
        Player player3 = new Player("次郎", "Hero", 200, 80, 30, 20, 25);
        player3.showStatus();
    }
}

実行結果:

✅ 太郎(初心者)が登録されました
========================================
名前: 太郎 (Beginner)
HP: 100/100 | MP: 50/50
攻撃: 10 | 魔力: 10 | 防御: 10
========================================

✅ 花子(Mage)が登録されました
========================================
名前: 花子 (Mage)
HP: 80/80 | MP: 100/100
攻撃: 8 | 魔力: 25 | 防御: 5
========================================

✅ 次郎(カスタムHero)が登録されました
========================================
名前: 次郎 (Hero)
HP: 200/200 | MP: 80/80
攻撃: 30 | 魔力: 20 | 防御: 25
========================================

どのコンストラクタを呼ぶかは、引数の数と型で自動判別されます。

デフォルトコンストラクタ

default_constructor(2).png

デフォルトコンストラクタとは?

デフォルトコンストラクタとは、引数を持たないコンストラクタのことです。

public Player() {
    // 引数なし
}

重要なルール

ルール1:コンストラクタを一切書かない場合

public class Player {
    String name;
    int hp;
    
    // コンストラクタを書いていない
}

Javaコンパイラが自動的にデフォルトコンストラクタを生成してくれます。

以下のコードが自動追加されます:

public Player() {
    // 何もしない(フィールドはデフォルト値で初期化される)
}

だから、以下のコードが動作します:

Player player = new Player();  // OK!自動生成されたコンストラクタが呼ばれる

ルール2:コンストラクタを1つでも書いた場合

public class Player {
    String name;
    int hp;
    
    // 引数ありのコンストラクタを定義
    public Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }
}

デフォルトコンストラクタは自動生成されません。

以下のコードはエラーになります:

Player player = new Player();  // ❌ エラー!引数なしのコンストラクタが存在しない

エラーメッセージ:

エラー: コンストラクタPlayerを見つけられません
  シンボル:   コンストラクタ Player()

引数なしでも作成できるようにするには?

明示的にデフォルトコンストラクタを書きます:

/**
 * プレイヤークラス
 */
public class Player {
    String name; // 名前
    int hp;      // HP
    
    /**
     * デフォルトコンストラクタ
     * 引数なしで作成する場合のデフォルト値を設定
     */
    public Player() {
        this.name = "名無し";
        this.hp = 100;
        System.out.println("✅ デフォルトプレイヤーが作成されました");
    }
    
    /**
     * 引数ありコンストラクタ
     */
    public Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
        System.out.println("✅ " + name + "が作成されました");
    }
}

これで両方の作成方法が使えます:

Player player1 = new Player();               // OK!デフォルトコンストラクタ
Player player2 = new Player("勇者", 150);    // OK!引数ありコンストラクタ

this()によるコンストラクタチェイン

constructor_chaining_v2.png

複数のコンストラクタを書くと、同じような初期化コードが重複します。

コードの重複問題

public Player(String name) {
    this.name = name;
    this.job = "Beginner";
    this.hp = 100;      // 重複
    this.maxHp = 100;   // 重複
    this.attack = 10;   // 重複
    // ...
}

public Player(String name, String job) {
    this.name = name;
    this.job = job;
    this.hp = 100;      // 重複
    this.maxHp = 100;   // 重複
    this.attack = 10;   // 重複
    // ...
}

問題点:

  • 同じような初期化処理が複数箇所に分散
  • 修正が大変(this.hpを100から80に変更したい場合、全コンストラクタを修正する必要がある)

解決策:this()でコンストラクタを呼び出す

this() を使うと、同じクラスの別のコンストラクタを呼び出せます。

/**
 * プレイヤークラス
 */
public class Player {
    String name; // 
    String job;  // 
    int hp;      // 
    int maxHp;   // 
    int attack;  // 
    
    /**
     * 最も詳細なコンストラクタ(メインコンストラクタ)
     * すべての初期化処理をここに集約する
     */
    public Player(String name, String job, int hp, int attack) {
        this.name = name;
        this.job = job;
        this.hp = hp;
        this.maxHp = hp;
        this.attack = attack;
        
        System.out.println("✅ " + name + "(" + job + ")HP:" + hp + " 攻撃:" + attack);
    }
    
    /**
     * 名前と職業のみ指定
     * デフォルトのHP、攻撃力で別のコンストラクタを呼び出す
     */
    public Player(String name, String job) {
        // this()で最も詳細なコンストラクタを呼び出す
        this(name, job, 100, 10);  // デフォルト値を渡す(HP:100、攻撃力:10)
    }
    
    /**
     * 名前のみ指定
     * デフォルトの職業で別のコンストラクタを呼び出す
     */
    public Player(String name) {
        // this()で名前と職業のみ指定のコンストラクタを呼び出す
        this(name, "Beginner"); 
    }
}

this()の重要なルール

ルール1:コンストラクタの最初の行に書く

public Player(String name) {
    System.out.println("処理1");  // ❌ エラー!this()より前に処理を書けない
    this(name, "Beginner");
}

正しい書き方:

public Player(String name) {
    this(name, "Beginner");  // ✅ 最初の行
    System.out.println("処理1");  // this()の後ならOK
}

ルール2:1つのコンストラクタで1回だけ

public Player(String name) {
    this(name, "Beginner");  // 1回目
    this(name, "Warrior");   // ❌ エラー!2回呼べない
}

ルール3:循環参照は禁止

public Player(String name) {
    this(name, "Beginner");  // コンストラクタ2を呼ぶ
}

public Player(String name, String job) {
    this(name);  // ❌ エラー!コンストラクタ1を呼ぶ → 無限ループ
}

実行例

/**
 * ゲームのメインクラス
 */
public class GameMain {
    public static void main(String[] args) {
        
        // パターン1:名前のみ → this()でデフォルト値が自動設定される
        Player player1 = new Player("太郎");
        
        // パターン2:名前と職業 → this()でデフォルトHP、攻撃力が設定される
        Player player2 = new Player("花子", "Mage");
        
        // パターン3:全指定 → 直接メインコンストラクタが呼ばれる
        Player player3 = new Player("次郎", "Warrior", 150, 20);
    }
}

実行結果:

✅ 太郎(Beginner)HP:100 攻撃:10
✅ 花子(Mage)HP:100 攻撃:10
✅ 次郎(Warrior)HP:150 攻撃:20

メリット:

  • 初期化処理が1箇所に集約される
  • 修正が簡単になる
  • コードの重複が減る

初期化の順序

インスタンスが作成されるとき、以下の順序で初期化が進みます:

初期化の流れ

/**
 * プレイヤークラス
 */
public class Player {
    
    // ① フィールド宣言時の初期化
    String name = "デフォルト名";
    int hp = 50;
    
    // ② コンストラクタ
    public Player(String name, int hp) {
        this.name = name;  // ③ 引数の値で上書き
        this.hp = hp;
    }
}

実行順序:

  1. メモリ確保

    • ヒープ領域にインスタンス用のメモリが確保される
  2. フィールドのデフォルト初期化

    • すべてのフィールドがデフォルト値で初期化される
    • int → 0, boolean → false, 参照型 → null
  3. フィールド宣言時の初期化式が実行される

    • String name = "デフォルト名";
    • int hp = 50;
  4. コンストラクタが実行される

    • 引数で渡された値がフィールドに設定される
    • 最終的に、引数の値が優先される

結論:コンストラクタの値が最終的な値になる

初学者がよくハマるポイント

❌ 間違い1:コンストラクタに戻り値の型を書いてしまう

public void Player(String name) {  // ❌ voidを書いてはダメ!
    this.name = name;
}

エラー:
これはコンストラクタではなく、「Playerという名前の普通のメソッド」として認識されます。

正しい書き方:

public Player(String name) {  // ✅ 戻り値の型を書かない
    this.name = name;
}

❌ 間違い2:コンストラクタ名がクラス名と違う

public class Player {
    
    public Plyer(String name) {  // ❌ スペルミス!
        this.name = name;
    }
}

エラー:
これも普通のメソッドとして認識されます。
new Player()としてもこのメソッドは呼ばれません。

正しい書き方:

public class Player {
    
    public Player(String name) {  // ✅ クラス名と完全一致
        this.name = name;
    }
}

❌ 間違い3:this()を最初の行以外で呼ぶ

public Player(String name) {
    System.out.println("初期化中...");  // ❌ これが先にある
    this(name, "Beginner");  // ❌ エラー!
}

エラーメッセージ:

エラー: コンストラクタ呼出し文は、コンストラクタ内の最初の文である必要があります

正しい書き方:

public Player(String name) {
    this(name, "Beginner");  // ✅ 最初の行
    System.out.println("初期化中...");  // this()の後ならOK
}

❌ 間違い4:thisを付け忘れる

public Player(String name, int hp) {
    name = name;  // ❌ フィールドに代入されない
    hp = hp;      // ❌ フィールドに代入されない
}

何が起きる?

  • 引数nameに引数nameを代入 → 意味なし
  • フィールドは初期値のまま(nullや0)

正しい書き方:

public Player(String name, int hp) {
    this.name = name;  // ✅ フィールドに代入
    this.hp = hp;      // ✅ フィールドに代入
}

デバッグのヒント

コンストラクタが呼ばれているか確認する

public Player(String name, String job) {
    System.out.println(">>> コンストラクタが呼ばれました");
    System.out.println("    引数name: " + name);
    System.out.println("    引数job: " + job);
    
    this.name = name;
    this.job = job;
    
    System.out.println(">>> 初期化完了");
}

このようにprintlnを入れると、コンストラクタが正しく呼ばれているか確認できます。

フィールドが正しく初期化されているか確認する

Player player = new Player("勇者", "Warrior");

// すぐに値を確認
System.out.println("name: " + player.name);
System.out.println("job: " + player.job);

もしnull0が表示されたら、コンストラクタの初期化処理に問題があります。


practice_problems_banner.png

実際に手を動かして、理解を深めましょう!

基本問題

問題1:基本的なコンストラクタを作ろう

以下の要件を満たすEnemyクラスを作成してください。

要件:

  • フィールド:String name, int hp, int attack
  • コンストラクタ:名前、HP、攻撃力を引数で受け取り、フィールドに設定する
  • メソッド:showStatus()で情報を表示する

使用例:

Enemy slime = new Enemy("スライム", 30, 5);
slime.showStatus();

期待される出力:

名前: スライム
HP: 30
攻撃力: 5

問題2:デフォルトコンストラクタを追加しよう

問題1のEnemyクラスに、引数なしのデフォルトコンストラクタを追加してください。

仕様:

  • 引数なしで作成した場合、以下のデフォルト値を設定する
    • name: "名無しの敵"
    • hp: 10
    • attack: 1

使用例:

Enemy defaultEnemy = new Enemy();
defaultEnemy.showStatus();

期待される出力:

名前: 名無しの敵
HP: 10
攻撃力: 1

応用問題

問題3:コンストラクタをオーバーロードしよう

以下の3つのコンストラクタを持つItemクラスを作成してください。

要件:

  • フィールド:String name, int price, String description
  • コンストラクタ1:名前のみ(価格は0、説明は"説明なし")
  • コンストラクタ2:名前と価格(説明は"説明なし")
  • コンストラクタ3:名前、価格、説明のすべてを指定

使用例:

Item item1 = new Item("薬草");
Item item2 = new Item("薬草", 10);
Item item3 = new Item("薬草", 10, "HPを20回復する");

問題4:this()を使ってコードを整理しよう

問題3のItemクラスを、this()を使ってリファクタリングしてください。

ヒント:

  • 最も詳細なコンストラクタ(3つの引数を持つもの)をメインコンストラクタにする
  • 他のコンストラクタはthis()でメインコンストラクタを呼ぶ

期待される構造:

public Item(String name) {
    this(name, 0);  // コンストラクタ2を呼ぶ
}

public Item(String name, int price) {
    this(name, price, "説明なし");  // コンストラクタ3を呼ぶ
}

public Item(String name, int price, String description) {
    // メインの初期化処理
    this.name = name;
    this.price = price;
    this.description = description;
}

問題5:職業システムを拡張しよう

本文で作成したPlayerクラスに、新しい職業「盗賊(Thief)」を追加してください。

盗賊のステータス:

  • HP: 110
  • MP: 40
  • 攻撃力: 18
  • 魔力: 8
  • 防御力: 8

テストコード:

Player thief = new Player("カイト", "Thief");
thief.showStatus();

期待される出力:

✅ カイト(Thief)が登録されました
========================================
名前: カイト
職業: Thief
----------------------------------------
HP: 110 / 110
MP: 40 / 40
----------------------------------------
攻撃力: 18
魔力: 8
防御力: 8
========================================

summary_banner.png

お疲れ様でした!第4回では、コンストラクタについて詳しく学びました。

重要ポイント:

  1. コンストラクタはインスタンス作成時に自動実行される

    • newでインスタンスを作るとき、必ず呼ばれる
    • 主な役割は「初期化」
  2. コンストラクタの書き方

    • メソッド名はクラス名と同じ
    • 戻り値の型を書かない
    • 引数で初期値を受け取れる
    • thisを使ってフィールドに値を設定
  3. コンストラクタのオーバーロード

    • 引数の数や型が違えば、複数定義できる
    • 作成方法のバリエーションが増える
  4. デフォルトコンストラクタ

    • コンストラクタを書かないと自動生成される
    • 1つでも書いたら自動生成されない
  5. this()によるコンストラクタチェイン

    • 同じクラスの別のコンストラクタを呼べる
    • コードの重複を減らせる
    • 必ず最初の行に書く

コンストラクタを使うメリット:

  • 初期化忘れを防げる
  • コードが短くなる
  • 安全にインスタンスを作成できる

next_episode_preview_banner-1.png

第5回:カプセル化 - データを守る技術

次回は、オブジェクト指向の重要な概念「カプセル化」を学びます。

現在のコードには、こんな問題があります:

Player hero = new Player("勇者", "Warrior");
hero.hp = -100;  // ❌ マイナスのHPを設定できてしまう!
hero.job = null;  // ❌ nullを設定できてしまう!

これを防ぐために、

  • アクセス修飾子(private, public)
  • getter/setterメソッド
  • バリデーション(値のチェック)

を学びます。

「データを守る」技術を身につけましょう!


reference_materials_banner-1.png


series_list_banner-1.png


© 2025 Java Quest - オブジェクト指向って何?RPGで理解する超入門
All Rights Reserved.

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?