質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.58%

親クラスの変数が参照されてしまう。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,598

score 21

今、javaの練習でパワプロ君のサクセスのようなものを作っています。
Playerクラス(選手全員の親クラス)を継承したHeroクラス(主人公を生み出す)の初期能力値についてです。
Heroクラスがインスタンス化されるときに、乱数で初期値が決まるようにしました。しかし、Mainのクラスで主人公の能力値を見るために、Playerクラスから継承したgetParameterメソッドを使うと、Playerクラスでとりあえず設定された初期値が戻り値として返されてしまいます。どうしたらいいでしょうか。

HeroクラスでgetParameterメソッドをオーバーライドすることも考えましたが、Playerクラスでのメソッドをそのまま継承できた方が今後楽そうです。よろしくお願いします。

[追記]
Playerを継承したクラスのインスタンスはそれぞれの能力値を持っていて、Heroクラスだけはランダムで初期値を。他の子クラスは定数で初期値を決めたいです。

public abstract class Player implements Character{
    int HP = 0;
    int condition = 0; //調子。0-4の5段階
    int meet = 0; //ミート
    int power = 0; //パワー
    int speed = 0; //走力
    int shoulder = 0; //肩力
    int defense = 0; //守備
    int ballSpeed = 0; //球速
    int control = 0; //コントロール
    int[] breakingBall = {0, 0, 0, 0, 0}; //変化球1-5の5段階でスライダー、カーブ、フォーク、シンカー、シュート

    abstract void practice(int numberOfPra);

/*能力値を取得する
*/
    String getParameter() {
        String conditionEva = "";

        switch(condition){
            case 0: conditionEva = "絶不調";
            break;
            case 1: conditionEva = "悪い";
            break;
            case 2: conditionEva = "普通";
            break;
            case 3: conditionEva = "良い";
            break;
            case 4: conditionEva = "絶好調";
            break;
        }

        String ability = "調子:" + conditionEva + ", ミート:" + judge(meet) + ", パワー:" + judge(power) 
        + ", 走力:" + judge(speed) + ", 肩力:" + judge(shoulder) + ", 守備力:" + judge(defense) + ", 球速:" + ballSpeed + "km, コントロール" + judge(control)
        + ", ←:" + breakingBall[0] + ", ↙:" + breakingBall[1] + ", ↓:" + breakingBall[2]
        + ", ↘:" + breakingBall[3] + ", ︎→:" + breakingBall[4];
        return ability;
    }

/*能力値をSABCDEFGで判断する
*/
    String judge(int sample){
        if (sample < 10){
            return "G";//0-9
        }
        else if(sample < 20){
            return "F";//10-19
        }
        else if(sample < 30){
            return "E";//20-29
        }
        else if(sample < 40){
            return "D";//30-39
        }
        else if(sample < 50){
            return "C";//40-49
        }
        else if(sample < 75){
            return "B";//51-74
        }
        else if(sample < 100){
            return "A";//75-99
        }
        else if(sample == 100){
            return "S";
        }
        return "-";
    }

    /*以下、全てゲッターとセッターだったので省略
     */

}
public class Hero extends Player {
    private static String name;
    private int HP = 0;//体力
    private int condition = 2; //調子。0-4の5段階
    private int meet = 0; //ミート
    private int power = 0; //パワー
    private int speed = 0; //走力
    private int shoulder = 0; //肩力
    private int defense = 0; //守備
    private int ballSpeed = 100; //球速
    private int control = 0; //コントロール
    private static int[] breakingBall = {0, 0, 0, 0, 0}; //変化球0-4でスライダー、カーブ、フォーク、シンカー、シュート
    private int sliderCounter = 0;
    private int curveCounter = 0;
    private int forkCounter = 0;
    private int sinkerCounter = 0;
    private int hardSinkerCounter = 0;

    public Hero(String name){
        this.name = name;
        this.HP = 100;

        //乱数で能力の初期値を決める。
        Random random = new Random();
        condition = 2;
        meet = random.nextInt(31);
        power = random.nextInt(31);
        speed = random.nextInt(21) + 90;
        shoulder = random.nextInt(31);
        defense = random.nextInt(31);
        ballSpeed = random.nextInt(31);
        control = random.nextInt(31);
        breakingBall = new int[]{random.nextInt(2), random.nextInt(2), random.nextInt(2), random.nextInt(2), random.nextInt(2)}; //スライダー、カーブ、フォーク、シンカー、シュート
    }

//休むメソッドです。質問には関係ないので省略
    public void rest(Hero h){

    }

//練習メソッド。質問には関係ないので省略
    public void practice(int numberOfPra){
    }

    //HPが25以下で約50%で怪我。変化球以外の能力値が減少。質問には関係ないので省略
    public void judgInjury() {
    }

//以下全てゲッターセッターなので省略


}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

子クラスから親クラスのメソッドを呼ぶと親クラスのフィールドを参照します。

getParameterを継承しないのであれば、Heroクラスの「name・HP・condition・meet・power・speed・shoulder・defense・ballSpeed・control・breakingBall」を削除し、コンストラクタで親クラスの該当フィールドにランダム値を与えるようにしましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/05 11:09

    なるほど。継承しなくてもそのような方法があるんですね。ありがとうございます。

    キャンセル

+1

この回答は間違っていました。


Player.getParameterの宣言がint HP = 0;String getParameter()となっているために、これはpackage privateとなっていて、Heroには継承されません。

protected、あるいはpublicにしてきちんと継承させましょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/05 11:08

    継承できてないんですか??オーバーライドしない限り全て継承されると思ってました。ちょっと勉強してきます。

    キャンセル

  • 2018/02/05 11:14

    パッケージプライベートであることは全く関係ないかと。

    キャンセル

  • 2018/02/05 11:16

    すみません、いま確認したら「同じパッケージ内で継承を行った場合、package privateなものも継承される」とのことでした。ありがとうございます。

    ただ、パッケージ外に出さないクラスは別として、継承されるものはprotected/publicをきちんと管理して置いたほうがいいのは間違いないです。

    キャンセル

+1

まず2つあります。

  • そもそもフィールドはオーバーライドされない。
  • 親クラス(Player)から子クラス(Hero)のフィールドを参照することはできない

PlayerクラスのgetParameterはHeroクラスの値を見ることはないので、初期値のままとなります。

追記
「継承されない」は、間違いでは?については、その通りです。
同名のフィールドを子クラスで定義した場合、親クラス、子クラスでそれぞれ同名のフィールドを持っています。
ですので、子クラス側で親クラスのフィールドに値を設定したつもりでも、子クラス側に設定されます。
継承自体されますが、他のクラスから参照できるかは、可視性によります。

対応としては、いくつかありますが。

前提としては、子クラス側のフィールドは削除します。

  1. YamakawaJunichiさんの言うとおり、子クラス側から親クラスの値を直接変更する
  2. 乱数設定の部分をPlayerのコンストラクタに実装する
  3. Playerに設定するパラメータを受け取るコンストラクタを用意する

が、考えられます。

子クラスで実装する場合、Playerクラスを継承した子クラスを作るごとに初期化処理を実装するので面倒です。
とはいえ、子クラスで独自の初期値を設定したいことがある場合、ランダムでは困ることがあるかもしれません。

子クラスから呼べるセッターを用意する場合、上記1の方法とほぼ同じです。
セッターで値を変更できるようにしたくないなら、2と3両方コンストラクタを用意すれば、
通常時はデフォルトコンストラクタで、ランダムに値を設定する。
特定の値を設定したい場合は、引数つきのコンストラクタを呼べばよいです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/05 16:58

    もしかして、Heroクラスのフィールドを消せば解決でしょうか?

    キャンセル

  • 2018/02/05 17:08

    YamakawaJunichiさんの回答そうですよね

    キャンセル

  • 2018/02/05 18:47

    なるほど。ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る