2
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

はじめに

こんにちは。Java Questの第3回へようこそ!

前回は、インスタンスと参照、そして配列について学びました。
複数のキャラクターをパーティとして管理できるようになりましたね。

今回は、クラスの中身である「フィールド」と「メソッド」について、さらに深く掘り下げていきます。

受講生からよく質問を受けるのが:
「フィールドとローカル変数って何が違うの?」
「staticって何?いつ使うの?」
「thisって何のためにあるの?」
「同じ名前のメソッドを複数作れるの?」

これらの疑問、今回で全部解決します!

この記事で一緒に学ぶこと:

  • フィールドとローカル変数の違い
  • staticキーワードの意味と使い方
  • thisキーワードの正体
  • メソッドのオーバーロード
  • アクセス修飾子の基本

所要時間: 約15〜20分です。実践的な内容が多いので、コードを実際に動かしながら読むと理解が深まります。

前提知識: 第1回第2回の内容を理解していることを前提とします。

第1回・第2回をまだ読んでいない方は、先にそちらをご覧ください:
👉 第1回:オブジェクト指向って何?RPGで理解する超入門
👉 第2回:オブジェクト指向って何?RPGで理解する超入門 (配列とループ)


今回のクエスト:冒険者ギルドを作ろう

guild_system_v2.png

今回は、冒険者たちが所属する「ギルド」を作ります。

ギルドには:

  • 全員で共有する情報:ギルド名、総メンバー数、ギルドレベル
  • 個人の情報:名前、職業、HP、攻撃力

この「共有」と「個別」の違いを理解することが、今回の最大のポイントです。

フィールドとローカル変数の違い

まず、受講生が最もつまずきやすい「フィールド」と「ローカル変数」の違いから見ていきましょう。

field_vs_local_v2.png

基本的なコード例

Player.java
/**
 * フィールドとローカル変数の違いを示すサンプル
 */
public class Player {
    
    // ========================================
    // フィールド(インスタンス変数)
    // クラス全体で使える変数
    // ========================================
    
    /** プレイヤーの名前 */
    String name;
    
    /** プレイヤーの体力 */
    int hp;
    
    /** プレイヤーの最大体力 */
    int maxHp;
    
    // ========================================
    // メソッド
    // ========================================
    
    /**
     * HPを回復するメソッド
     */
    void heal() {
        // ----------------------------------------
        // ローカル変数(メソッド内だけの変数)
        // このメソッド内でしか使えない
        // ----------------------------------------
        int amount = 30;  // 回復量(ローカル変数)
        
        // フィールドhpを回復量分増やす
        // hp = hp + amountと同じ意味
        hp += amount;
        
        // 最大HPを超えないようにする
        if (hp > maxHp) {
            hp = maxHp;
        }
        
        System.out.println(name + "は " + amount + " HP回復した!");
        System.out.println("現在のHP: " + hp + " / " + maxHp);
        
        // メソッドを抜けると、amountは消える
    }
    
    /**
     * ダメージを受けるメソッド
     * @param damage 受けるダメージ量
     */
    void takeDamage(int damage) {
        // damageはパラメータ(ローカル変数の一種)
        // このメソッド内でしか使えない

        // hp = hp - damageと同じ意味
        hp -= damage;

        // ここではマイナスにならないように0を代入
        // HPは0を最小値とする
        if (hp < 0) {
            hp = 0;
        }
        
        System.out.println(name + "は " + damage + " のダメージを受けた!");
        System.out.println("残りHP: " + hp + " / " + maxHp);
        
        // メソッドを抜けると、damageは消える
    }
    
    /**
     * レベルアップ時にHPを増やすメソッド
     */
    void levelUp() {
        // ローカル変数
        int hpIncrease = 20;  // HP増加量
        
        // フィールドmaxHpを増やす
        maxHp = maxHp + hpIncrease;
        
        // 現在のHPも増やす
        hp = hp + hpIncrease;
        
        System.out.println(name + "はレベルアップした!");
        System.out.println("最大HPが " + hpIncrease + " 増加!");
        
        // hpIncreaseはここで消える
    }
}

フィールドとローカル変数の違い

項目 フィールド ローカル変数
宣言場所 クラス直下(メソッドの外) メソッド内、for文内など
スコープ クラス全体 宣言された{}ブロック内のみ
寿命 インスタンスが存在する間 メソッド終了まで
初期値 自動的に設定される(int→0, String→null) 手動で設定必要
アクセス 全メソッドからアクセス可能 宣言されたブロック内のみ
メモリ ヒープ領域 スタック領域

実行例

FieldTest.java
/**
 * フィールドとローカル変数の動作確認
 */
public class FieldTest {
    
    /**
     * メインメソッド
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        
        Player hero = new Player();
        hero.name = "勇者";
        hero.hp = 100;
        hero.maxHp = 100;
        
        System.out.println("=== 初期状態 ===");
        System.out.println("HP: " + hero.hp + " / " + hero.maxHp);
        
        System.out.println("\n=== ダメージを受ける ===");
        hero.takeDamage(40);
        
        System.out.println("\n=== 回復 ===");
        hero.heal();
        
        System.out.println("\n=== レベルアップ ===");
        hero.levelUp();
        
        // フィールドはここでもアクセスできる
        System.out.println("\n現在のHP: " + hero.hp);
        
        // ローカル変数amountやhpIncreaseはここではアクセスできない
        // System.out.println(amount);  // エラー!
    }
}

重要なポイント:

  • フィールドは「プレイヤーの状態」を表すデータ
  • ローカル変数は「一時的な計算」に使うデータ
  • フィールドは全メソッドから参照できるが、ローカル変数はメソッド内だけ

staticキーワード:全員で共有する情報

ギルドを作る上で重要なのがstaticキーワードです。
これは「全インスタンスで共有する」という意味です。

static_shared_v2.png

staticフィールドの基本

Player.java
/**
 * 冒険者クラス(ギルド機能付き)
 */
public class Player {
    
    // ========================================
    // staticフィールド(クラス変数)
    // 全インスタンスで共有される
    // ========================================
    
    /** ギルド名(全員で共有) */
    static String guildName = "勇者ギルド";
    
    /** ギルドの総メンバー数(全員で共有) */
    static int totalMembers = 0;
    
    /** ギルドレベル(全員で共有) */
    static int guildLevel = 1;
    
    // ========================================
    // インスタンスフィールド
    // 各冒険者ごとに異なる
    // ========================================
    
    /** 冒険者の名前(個別) */
    String name;
    
    /** 冒険者のHP(個別) */
    int hp;
    
    /** 冒険者の攻撃力(個別) */
    int attack;
    
    // ========================================
    // コンストラクタ
    // ========================================
    
    /**
     * コンストラクタ:新しい冒険者を作成
     * @param name 冒険者の名前
     * @param hp 初期HP
     * @param attack 攻撃力
     */
    public Player(String name, int hp, int attack) {
        this.name = name;
        this.hp = hp;
        this.attack = attack;
        
        // 新しいメンバーが加入したので、総メンバー数を増やす
        totalMembers++;
        
        System.out.println(name + "が " + guildName + " に加入しました!");
        System.out.println("現在のメンバー数: " + totalMembers + "人");
    }
    
    // ========================================
    // staticメソッド
    // ========================================
    
    /**
     * ギルド情報を表示(staticメソッド)
     */
    static void showGuildInfo() {
        System.out.println("===== ギルド情報 =====");
        System.out.println("ギルド名: " + guildName);
        System.out.println("メンバー数: " + totalMembers + "人");
        System.out.println("ギルドレベル: " + guildLevel);
        System.out.println("=====================");
    }
    
    /**
     * ギルドレベルを上げる(staticメソッド)
     */
    static void levelUpGuild() {
        guildLevel++;
        System.out.println(guildName + " のレベルが " + guildLevel + " に上がった!");
    }
    
    // ========================================
    // インスタンスメソッド
    // ========================================
    
    /**
     * 自己紹介
     */
    void introduce() {
        System.out.println("私は " + name + "、" + guildName + " の一員です!");
        System.out.println("HP: " + hp + ", 攻撃力: " + attack);
    }
}

staticの使い方

GuildExample.java
/**
 * staticフィールドとstaticメソッドの使用例
 */
public class GuildExample {
    
    /**
     * メインメソッド
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        
        System.out.println("=== ギルド設立 ===\n");
        
        // ギルド情報を表示(インスタンスなしで呼べる)
        Player.showGuildInfo();
        
        System.out.println("\n=== メンバー募集 ===\n");
        
        // 冒険者を3人作成
        Player hero1 = new Player("戦士アルフレッド", 120, 20);
        System.out.println();
        
        Player hero2 = new Player("魔法使いメルリン", 80, 30);
        System.out.println();
        
        Player hero3 = new Player("僧侶エレナ", 90, 10);
        System.out.println();
        
        // ギルド情報を再度表示
        Player.showGuildInfo();
        
        System.out.println("\n=== 自己紹介タイム ===\n");
        
        // 各メンバーが自己紹介
        hero1.introduce();
        System.out.println();
        
        hero2.introduce();
        System.out.println();
        
        hero3.introduce();
        System.out.println();
        
        System.out.println("=== ギルドレベルアップ ===\n");
        
        // ギルドレベルを上げる
        Player.levelUpGuild();
        System.out.println();
        
        // 全員のギルドレベルが変わっている
        System.out.println(hero1.name + "の所属ギルドレベル: " + Player.guildLevel);
        System.out.println(hero2.name + "の所属ギルドレベル: " + Player.guildLevel);
        System.out.println(hero3.name + "の所属ギルドレベル: " + Player.guildLevel);
    }
}

実行結果

=== ギルド設立 ===

===== ギルド情報 =====
ギルド名: 勇者ギルド
メンバー数: 0人
ギルドレベル: 1
=====================

=== メンバー募集 ===

戦士アルフレッドが 勇者ギルド に加入しました!
現在のメンバー数: 1人

魔法使いメルリンが 勇者ギルド に加入しました!
現在のメンバー数: 2人

僧侶エレナが 勇者ギルド に加入しました!
現在のメンバー数: 3人

===== ギルド情報 =====
ギルド名: 勇者ギルド
メンバー数: 3人
ギルドレベル: 1
=====================

=== 自己紹介タイム ===

私は 戦士アルフレッド、勇者ギルド の一員です!
HP: 120, 攻撃力: 20

私は 魔法使いメルリン、勇者ギルド の一員です!
HP: 80, 攻撃力: 30

私は 僧侶エレナ、勇者ギルド の一員です!
HP: 90, 攻撃力: 10

=== ギルドレベルアップ ===

勇者ギルド のレベルが 2 に上がった!

戦士アルフレッドの所属ギルドレベル: 2
魔法使いメルリンの所属ギルドレベル: 2
僧侶エレナの所属ギルドレベル: 2

staticのポイント

staticフィールド:

  • クラスに1つだけ存在
  • 全インスタンスで共有される
  • クラス名.フィールド名でアクセス
  • インスタンスを作らなくてもアクセス可能

staticメソッド:

  • クラスに1つだけ存在
  • クラス名.メソッド名()で呼び出し
  • インスタンスフィールドにはアクセスできない
  • staticフィールドにはアクセスできる

いつ使う?

  • 全インスタンスで共有したい情報(カウンター、定数など)
  • ユーティリティメソッド(Math.max()など)
  • インスタンスに依存しない処理

thisキーワード:自分自身を指す

thisは「自分自身のインスタンス」を指すキーワードです。

this_keyword.png

thisが必要な理由

Player.java
/**
 * thisキーワードの必要性を示すサンプル
 */
public class Player {
    
    /** プレイヤーの名前 */
    String name;
    
    /** プレイヤーのHP */
    int hp;
    
    // ========================================
    // ❌ 間違った例(thisなし)
    // ========================================
    
    /**
     * 名前を設定(thisなし)
     * @param name 設定する名前
     */
    void setNameWrong(String name) {
        // どっちのnameか分からない!
        // パラメータnameがフィールドnameを隠してしまう
        name = name;  // これは何もしていない!
        
        // 実際には「パラメータname = パラメータname」になっている
    }
    
    // ========================================
    // ✅ 正しい例(thisあり)
    // ========================================
    
    /**
     * 名前を設定(thisあり)
     * @param name 設定する名前
     */
    void setName(String name) {
        // this.name = フィールド
        // name = パラメータ
        this.name = name;  // 明確に区別できる!
    }
    
    /**
     * HPを設定(thisあり)
     * @param hp 設定するHP
     */
    void setHp(int hp) {
        // フィールドhpにパラメータhpを代入
        this.hp = hp;
    }
    
    /**
     * プレイヤー情報を表示
     */
    void showInfo() {
        // thisは省略可能(フィールドとローカル変数が被らない場合)
        System.out.println("名前: " + name);  // this.nameと同じ
        System.out.println("HP: " + hp);      // this.hpと同じ
        
        // でも、明示的にthisを書くのも良い習慣
        System.out.println("名前: " + this.name);
        System.out.println("HP: " + this.hp);
    }
}

thisの動作確認

ThisExample.java
/**
 * thisキーワードの動作確認
 */
public class ThisExample {
    
    /**
     * メインメソッド
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        
        Player hero = new Player();
        
        System.out.println("=== 間違った方法でnameを設定 ===");
        hero.setNameWrong("勇者");
        hero.showInfo();  // nameがnullのまま!
        
        System.out.println("\n=== 正しい方法でnameを設定 ===");
        hero.setName("勇者");
        hero.showInfo();  // 正しく設定される
        
        System.out.println("\n=== HPも設定 ===");
        hero.setHp(100);
        hero.showInfo();
    }
}

thisのその他の使い方

Player.java
/**
 * thisの応用例
 */
public class Player {
    
    String name;
    int hp;
    int attack;
    
    /**
     * コンストラクタ:全パラメータ指定
     * @param name 名前
     * @param hp HP
     * @param attack 攻撃力
     */
    public Player(String name, int hp, int attack) {
        // thisでフィールドとパラメータを区別
        this.name = name;
        this.hp = hp;
        this.attack = attack;
    }
    
    /**
     * コンストラクタ:名前のみ指定
     * @param name 名前
     */
    public Player(String name) {
        // this()で別のコンストラクタを呼び出し
        this(name, 100, 10);  // デフォルト値を設定
    }
    
    /**
     * 自分自身を返すメソッド(メソッドチェーン用)
     * @param name 名前
     * @return 自分自身
     */
    Player setName(String name) {
        this.name = name;
        return this;  // 自分自身を返す
    }
    
    /**
     * HPを設定して自分自身を返す
     * @param hp HP
     * @return 自分自身
     */
    Player setHp(int hp) {
        this.hp = hp;
        return this;
    }
    
    /**
     * メソッドチェーンの例
     */
    public static void main(String[] args) {
        // メソッドチェーンで連続設定
        Player hero = new Player("勇者")
                        .setName("勇者アレン")
                        .setHp(120);
        
        hero.showInfo();
    }
}

thisのポイント:

  • this = 自分自身のインスタンス
  • フィールドとパラメータを区別するために使う
  • コンストラクタ内でよく使う
  • this() で別のコンストラクタを呼び出せる
  • return this でメソッドチェーンが可能

メソッドのオーバーロード:同じ名前、異なる引数

RPGでは、攻撃方法がいくつかありますよね。
「通常攻撃」「対象を指定して攻撃」「威力を指定して攻撃」など。

これを実装するのが「オーバーロード」です。

method_overload_v2.png

オーバーロードの基本

Player.java
/**
 * メソッドのオーバーロードを示すサンプル
 */
public class Player {
    
    String name;
    int hp;
    int attack;
    
    /**
     * コンストラクタ
     * @param name 名前
     * @param hp HP
     * @param attack 攻撃力
     */
    public Player(String name, int hp, int attack) {
        this.name = name;
        this.hp = hp;
        this.attack = attack;
    }
    
    // ========================================
    // オーバーロード:同じ名前のメソッドを複数定義
    // ========================================
    
    /**
     * 攻撃1:引数なし(ランダム攻撃)
     */
    void attack() {
        System.out.println(name + "の攻撃!");
        System.out.println("ランダムな敵に " + attack + " のダメージ!");
    }
    
    /**
     * 攻撃2:対象を指定
     * @param target 攻撃対象
     */
    void attack(Player target) {
        System.out.println(name + "の攻撃!");
        System.out.println(target.name + "に " + attack + " のダメージ!");

        // target.hp = target.hp - attack と同じ意味
        target.hp -= attack;
        
       // HPが0より小さいとき、0を代入
       if (target.hp < 0) {
            target.hp = 0;
        }
        
        System.out.println(target.name + "の残りHP: " + target.hp);
    }
    
    /**
     * 攻撃3:対象とダメージ量を指定
     * @param target 攻撃対象
     * @param damage ダメージ量
     */
    void attack(Player target, int damage) {
        System.out.println(name + "の強攻撃!");
        System.out.println(target.name + "に " + damage + " のダメージ!");

        // HPからダメージ量をマイナスする
        // target.hp = target.hp - damage と同じ意味
        target.hp -= damage;
        
        // HPが0より小さいとき、0を代入
        if (target.hp < 0) {
            target.hp = 0;
        }
        
        System.out.println(target.name + "の残りHP: " + target.hp);
    }
    
    /**
     * 攻撃4:複数の敵を攻撃
     * @param targets 攻撃対象の配列
     */
    void attack(Player[] targets) {
        System.out.println(name + "の全体攻撃!");
        
        for (int i = 0; i < targets.length; i++) {
            int damage = attack / 2;  // 全体攻撃は威力半減
            System.out.println(targets[i].name + "に " + damage + " のダメージ!");

            
            // HPからダメージ量をマイナスする
            // targets[i].hp = targets[i].hp - damage と同じ意味
            targets[i].hp -= damage;
            
            // HPが0より小さいとき、0を代入
            if (targets[i].hp < 0) {
                targets[i].hp = 0;
            }
        }
    }
    
    /**
     * 攻撃5:属性付き攻撃
     * @param target 攻撃対象
     * @param element 属性("火", "水", "雷"など)
     */
    void attack(Player target, String element) {
        System.out.println(name + "の" + element + "属性攻撃!");
        int damage = attack;
        
        // 属性によってダメージ補正
        if (element.equals("火")) {
            damage = (int)(attack * 1.5);
            System.out.println("炎が " + target.name + " を包む!");
        } else if (element.equals("水")) {
            damage = (int)(attack * 1.3);
            System.out.println("水流が " + target.name + " に襲いかかる!");
        } else if (element.equals("雷")) {
            damage = (int)(attack * 1.8);
            System.out.println("雷撃が " + target.name + " を貫く!");
        }
        
        System.out.println(target.name + "に " + damage + " のダメージ!");

        // HPからダメージ量をマイナスする
        // target.hp = target.hp - damage と同じ意味
        target.hp -= damage;

        // HPが0より小さいとき、0を代入
        if (target.hp < 0) {
            target.hp = 0;
        }
        
        System.out.println(target.name + "の残りHP: " + target.hp);
    }
}

オーバーロードの使用例

OverloadExample.java
/**
 * オーバーロードの動作確認
 */
public class OverloadExample {
    
    /**
     * メインメソッド
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        
        System.out.println("=== 戦闘準備 ===\n");
        
        // 味方(名前、HP、攻撃力)
        Player hero = new Player("勇者", 100, 20);
        
        // 敵(名前、HP、攻撃力)
        Player slime1 = new Player("スライム1", 30, 5);
        Player slime2 = new Player("スライム2", 30, 5);
        Player dragon = new Player("ドラゴン", 200, 30);
        
        // ========================================
        // 1. 引数なしのattack()
        // ========================================
        System.out.println("=== パターン1:ランダム攻撃 ===");
        hero.attack();
        System.out.println(); // 空行
        
        // ========================================
        // 2. 対象を指定するattack(target)
        // ========================================
        System.out.println("=== パターン2:対象指定攻撃 ===");
        hero.attack(slime1);
        System.out.println(); // 空行
        
        // ========================================
        // 3. 対象とダメージを指定するattack(target, damage)
        // ========================================
        System.out.println("=== パターン3:威力指定攻撃 ===");
        hero.attack(slime2, 50);
        System.out.println(); // 空行
        
        // ========================================
        // 4. 複数の敵を攻撃attack(targets[])
        // ========================================
        System.out.println("=== パターン4:全体攻撃 ===");
        Player[] enemies = {slime1, slime2, dragon};
        hero.attack(enemies);
        System.out.println(); // 空行
        
        // ========================================
        // 5. 属性攻撃attack(target, element)
        // ========================================
        System.out.println("=== パターン5:属性攻撃 ===");
        hero.attack(dragon, "雷");
        System.out.println(); // 空行
        
        // Javaが自動的に適切なメソッドを選んでくれる!
    }
}

オーバーロードのルール

✅ OK:オーバーロード可能

void attack()                        // 引数なし
void attack(Player target)           // 引数1つ(Player型)
void attack(Player target, int damage)  // 引数2つ(Player, int)
void attack(Player[] targets)        // 引数1つ(配列)
void attack(Player target, String element)  // 引数2つ(Player, String)

❌ NG:オーバーロード不可

void attack(Player target)
int attack(Player target)  // 戻り値の型が違うだけではダメ!

void attack(Player target)
void attack(Player enemy)  // パラメータ名が違うだけではダメ!

オーバーロードの条件:

  1. メソッド名が同じ
  2. 引数の数が異なる、または
  3. 引数の型が異なる
  4. 戻り値の型だけが違うのはNG
  5. パラメータ名だけが違うのはNG

Javaの選択ルール:

  • 呼び出し時の引数に最も合致するメソッドが自動選択される
  • 引数の数と型を見て判断
  • コンパイル時に決定される

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

❌ 間違い1:フィールドの初期化忘れ

public class Player {
    String name;
    int hp;
    
    void showInfo() {
        System.out.println(name + "のHP: " + hp);
    }
}

Player hero = new Player();
hero.showInfo();  // "nullのHP: 0" と表示される

対策:
コンストラクタで初期化、またはフィールド宣言時に初期値を設定

public class Player {
    String name = "名無し";  // デフォルト値
    int hp = 100;
    
    // またはコンストラクタで初期化
    public Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }
}

❌ 間違い2:staticメソッドからインスタンスフィールドへのアクセス

public class Player {
    String name;  // インスタンスフィールド
    
    static void showName() {
        System.out.println(name);  // エラー!
        // staticメソッドからインスタンスフィールドにはアクセスできない
    }
}

なぜエラー?
staticメソッドは「どのインスタンスのnameか」を特定できない

対策:
インスタンスをパラメータで渡す

public class Player {
    String name;
    
    static void showName(Player player) {
        System.out.println(player.name);  // OK!
    }
}

❌ 間違い3:thisの不適切な使用

public class Player {
    String name;
    
    static void setGuildName(String guildName) {
        this.guildName = guildName;  // エラー!
        // staticメソッドでthisは使えない
    }
}

なぜエラー?
thisは「自分自身のインスタンス」を指すが、staticメソッドにはインスタンスが存在しない

対策:
staticフィールドにはクラス名でアクセス

public class Player {
    static String guildName;
    
    static void setGuildName(String name) {
        Player.guildName = name;  // OK!
        // または単に guildName = name; でもOK
    }
}

デバッグのヒント

ローカル変数の未初期化エラー

void example() {
    int count;
    count++;  // エラー!変数が初期化されていません
}

解決方法:

void example() {
    int count = 0;  // 初期化する
    count++;  // OK!
}

オーバーロードの曖昧さ

void attack(int damage) { }
void attack(double damage) { }

attack(10);  // どっち? → int版が選ばれる

注意点:

  • 型変換が可能な場合、最も近い型のメソッドが選ばれる
  • 曖昧な場合はコンパイルエラーになる

staticとnon-staticの混同

public class Player {
    String name;
    static String guildName;
    
    void showInfo() {
        System.out.println(name);       // OK(インスタンスメソッドからインスタンスフィールド)
        System.out.println(guildName);  // OK(インスタンスメソッドからstaticフィールド)
    }
    
    static void showGuild() {
        System.out.println(guildName);  // OK(staticメソッドからstaticフィールド)
        System.out.println(name);       // エラー!(staticメソッドからインスタンスフィールド)
    }
}

覚え方:

  • インスタンスメソッド:すべてにアクセス可能
  • staticメソッド:staticなものだけアクセス可能

practice_problems_banner.png

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

基本問題

問題1: ギルドシステムを作成しよう

Playerクラスに以下の機能を追加してください。

要件:

  • staticフィールド:guildName(ギルド名)
  • staticメソッド:changeGuildName(String newName)
  • インスタンスメソッド:showGuildInfo()(自分の名前とギルド名を表示)

3人の冒険者を作成して、全員が同じギルドに所属していることを確認してください。

問題2: thisを使ってコンストラクタを作成しよう

以下の仕様でPlayerクラスのコンストラクタを作成してください。

public Player(String name, int hp, int attack) {
    // thisを使ってフィールドを初期化
}

応用問題

問題3: オーバーロードで回復メソッドを作成しよう

Playerクラスに、以下の3つのhealメソッドを作成してください。

  1. heal():固定値30で回復
  2. heal(int amount):指定した量だけ回復
  3. heal(Player healer):他のプレイヤーから回復してもらう(healer.attackの半分回復)

それぞれを実行して、動作を確認してください。

問題4: staticカウンターを実装しよう

Playerクラスに、以下の機能を追加してください。

仕様:

  • staticフィールド:createdCount(作成されたインスタンスの総数)
  • コンストラクタで、インスタンス作成時にcreatedCountを増やす
  • staticメソッド:showCreatedCount()(総作成数を表示)

5人の冒険者を作成して、作成数が正しくカウントされることを確認してください。

問題5: メソッドチェーンを実装しよう

Playerクラスに、以下のメソッドを追加してください。

Player setName(String name) {
    this.name = name;
    return this;
}

Player setHp(int hp) {
    this.hp = hp;
    return this;
}

Player setAttack(int attack) {
    this.attack = attack;
    return this;
}

メソッドチェーンで、1行でプレイヤーを設定できることを確認してください。

Player hero = new Player()
    .setName("勇者")
    .setHp(100)
    .setAttack(20);

まとめ

お疲れ様でした!第3回では、フィールドとメソッドについて深く学びました。

重要ポイント:

  1. フィールドとローカル変数の違い

    • フィールド:クラス全体で使える、インスタンスの状態
    • ローカル変数:メソッド内だけ、一時的な計算
  2. staticキーワード

    • 全インスタンスで共有される
    • クラス名でアクセス
    • インスタンスなしでも使える
  3. thisキーワード

    • 自分自身のインスタンスを指す
    • フィールドとパラメータを区別
    • コンストラクタの連鎖に使える
  4. メソッドのオーバーロード

    • 同じ名前、異なる引数
    • 引数の数や型で区別
    • Javaが自動的に選択
  5. アクセスの組み合わせ

    • インスタンスメソッド → すべてOK
    • staticメソッド → staticのみOK

受講生からよく聞く感想:
「staticとthisの違いが分かって、スッキリしました!」
「オーバーロードって便利ですね。攻撃メソッドが分かりやすくなりました」


next_episode_preview_banner-1.png

第4回:コンストラクタ - オブジェクトの初期化を極める

次回は、今回少し触れた「コンストラクタ」について、さらに詳しく学びます。

  • コンストラクタとは何か
  • オーバーロードされたコンストラクタ
  • デフォルトコンストラクタ
  • コンストラクタの連鎖
  • 初期化ブロック

冒険者の職業システムを実装していきます!


reference_materials_banner-1.png


series_list_banner-1.png


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

本記事は教育目的で作成されています。RPGの例を通じてプログラミング概念を楽しく学習できることを目指しています。

2
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
2
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?