

Personという抽象クラスの配列を用意しましたが、Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length
0というエラーで実行できません。  
Personは人の名前と所持金を保持します。

[code]

    abstract class Person{
        protected String names;
        protected int moneys;
    
        public Person(String name, int money){
            names = name;
            moneys = money;
        }
    
        void getName(){
            System.out.println("name:"+names);
        }
    
        void getMoney(){
            System.out.println("money:"+moneys);
        }
    
        void changeMoney(int used_money){
            moneys = moneys - used_money;
            if(moneys < 0){
                System.out.println("error:money cannot be less than 0");
            }
        } 
    
        void print(){
            System.out.println(names+" now has "+moneys+" yen");
        }
    
        abstract int getFee();
    
    }
    
[/code]

以下はバスの乗車時にお金を払えなかったら、人数がいっぱいだったら乗れないというようなコードです。見てほしいところは**をつけているvoid
getOn()のpassengers[pass_num++] = person;です。ここでエラーがでます。

[code]

    public class Bus extends Car{
        private static int pass_num = 1;
        private int pass_max;
        private static int fee_sum = 0;
    
        public Bus(int x){
            pass_max = x;
        }
    
        Person passengers[] = new Person[pass_max];
    
        int getBusNum(){
            return super.num;
        }
    
        void getOn(Person person){
            int fee = person.getFee();
            fee_sum += fee;
            if(person.moneys - fee >= 0 && pass_num < pass_max){
                person.moneys -= fee;
                *passengers[pass_num++] = person;*
                person.getName();
                person.getMoney();
            }else{
                System.out.println(person.names+" could not get on the bus");
    
            }
        }
    
        void getOff(Person pass){
            int k;
            int flag = 0;
            for(k=0;k<pass_num;k++){
                if((pass.names).equals(passengers[k])){
                    System.out.println(pass.names+" got off the bus");
                    passengers[k].names = "";
                    passengers[k].moneys = -1;
                    flag = 1;
                    break;
                }
            }
            if(flag == 0){
                System.out.println(pass.names+" was not on the bus");
            }
            flag = 0;
        }
    
        void printAllPassengers(){
            for(int j=0;j>pass_max;j++){
                if(passengers[j].moneys != -1){
                    System.out.println("name: "+passengers[j].names);
                }
            }
        }
    
        void printTotalFee(){
            System.out.println("sum of fee: "+fee_sum);
        }
    
    }
    
[/code]

またPersonクラスにはサブクラスがあり、このようになっています。

[code]

    public class Adult extends Person{
        int getFee(){
            return 200;
        }
        public Adult(String name, int money){
            super(name, money);
        }
    }
    
[/code]

似たようなクラスにChild, Seniorがあります。

調べてみた結果、passengerがNULLになっているとかPersonオブジェクトと結びついていないと色々考えましたが分かりませんでした。ご教授お願いします。

最後に、勉強を初めてまもないのでコードの稚拙さやプログラムしたい内容とかみ合っていないなど、指摘する点は多いと思いますがご容赦ください。


CC BY-SA 4.0
2020-05-15T09:10:01.483
66633
2020-05-16T01:04:50.390
35091
question
java
抽象クラスの配列の宣言の仕方が分かりません


全体がよく見えてこないので、これだけで問題が解消するのか不明ですが……

[code]

    public Bus(int x){
        pass_max = x;
    }
    
    Person passengers[] = new Person[pass_max];
    
[/code]

ここを

[code]

    public Bus(int x){
        pass_max = x;
        passengers[] = new Person[pass_max];
    }
    
    Person passengers[];
    
[/code]

としてみたらどうでしょうか？

`java.lang.ArrayIndexOutOfBoundsException` については解消できるかもしれません。


CC BY-SA 4.0
2020-05-15T09:25:24.980
66634
2020-05-15T09:31:13.483
2020-05-15T09:31:13.483
7290
7290
66633
answer

[code]

    public class Bus extends Car{
        private static int pass_num = 1;
        private int pass_max;
        private static int fee_sum = 0;
    
        public Bus(int x){
            pass_max = x;
        }
    
        Person passengers[] = new Person[pass_max];
    
[/code]

まずコンストラクタで `pass_max`の値を設定した後、それをもとに`Person`配列を確保しよう、という意図かと思いますが、実際にはそうなりません。  
必ずしも書いた順に実行されるわけではなく、優先度が決まっています。

今回の場合で言うと、先にフィールドが初期化された後、コンストラクタが呼ばれます。

つまり、

[code]

    Person passengers[] = new Person[pass_max];
    
[/code]

が実行されるとき、まだコンストラクタは実行されておらず、`int`型である`pass_max`フィールドは初期値`0`のままです。  
結果、配列の要素数は`0`個になります。

意図した順に実行するためには、`pass_max`を利用して初期化する処理もコンストラクタで行うようにします。

[code]

    public class Bus extends Car{
        private static int pass_num = 1;
        private final int pass_max;
        private static int fee_sum = 0;
    
        public Bus(int x){
            pass_max = x;
            passengers = new Person[pass_max];
        }
    
        final Person passengers[];
    
[/code]

定数には`final`を付与する習慣をつけておくと、こういった勘違いをコンパイルエラーで検知できるようになるので便利です。

参考:

  * [12.5. Creation of New Class Instances](https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.5) \- The Java® Language Specification

* * *

今回の問題とは関係ないのですが、本回答で登場した範囲のコードについてコメントすると、

  * `pass_num` は配列の添字として利用している変数なので初期値は`1`でなく`0`が妥当でしょう
  * おそらく `static` の意味を勘違いしています


CC BY-SA 4.0
2020-05-16T01:04:50.390
66655
2020-05-16T01:04:50.390
2808
66633
answer