2

明らかな何かが欠けているためにこれがどこかで答えられた場合は申し訳ありませんが、私はこれを何日もグーグルで検索しており、意味がないようです. 私は Javascript で 3 年の経験があり、現在 Java に取り掛かっているので、何かの基本的な概念などに遅れをとっていません。

これにはIntelliJを使用していますが、問題を指摘できません。クラス間の通信 (アクセス権とインスタンス化) は問題なく、コードの構文と変数の型も同様です。

他のクラスが使用する「読み取り専用」データを保持するだけの Data クラスがあります。

public class Data {
    // snip
    public static int[][] specs = {
      {6,1,6,40},
      {5,2,5,30},
      {5,3,4,40},
      {4,4,3,60}
   };
}

初期化時にこのデータを読み取る必要がある別のクラスがあります。

public class Soldier {
    // snip
    public int range;
    public Soldier() {
        int x = ...; // user input
        range = Data.specs[x][1];
    }
}

specs 配列自体には、定義されたとおりのデータが含まれています (つまり、配列は空ではありません)。x は specs 配列のインデックスとして有効です (つまり、0 <= x <= 3)。その型は int で、Test はspecs 配列 (デバッグ出力ステートメントですべて確認済み)。それでも、範囲の値を設定しようとすると(そのときだけ、その時点で)、「インデックスが範囲外です」というエラーが発生します。

配列を読み取ろうとしたときに何が問題なのか誰か教えてください。それとも、これは本当に奇妙で、コード全体を投稿する必要があると言っているのは正しいですか?

注: 小さな新しいテストでは、最初に配列から手動で選択した値を出力し、次に範囲の値を設定するようにコードを変更すると、コンソールにエラー ステートメントが出力され (そしてプログラムが終了し)、次のように表示されることも示されています。手動で選択した値を出力しますが、値を割り当ててから出力範囲を要求すると、エラーがスローされるだけです...それはまったく意味がありません!

編集: 上記のコードを編集しました。Test というクラスは、私のコードでは Soldier と呼ばれています (テキストベースのゲームを作成しています...)。完全なコード (かなり長い) がなくても問題ない場合は、以下にスタック トレースを示します。私のプログラムの基本的な構造は次のとおりです。

1) ブートには main メソッドが含まれ、新しいゲームをインスタンス化します

2) ゲームのインスタンス x チーム

3) 各チームがアーミーをインスタンス化する

4) 各軍は x 兵士をインスタンス化します

クラスの各インスタンスは、インスタンス化するクラスの属性として設定されます (たとえば、パブリック Army アーミー、および Team コンストラクター内のアーミー インスタンス化)。これは基本的に、後続のクラスをインスタンス化し、属性として割り当てるコンストラクターのカスケードです。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Army.<init>(Army.java:13)
at Team.<init>(Team.java:19)
at Game.<init>(Game.java:22)
at Boot.main(Boot.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)5

編集編集:これがセミフルコードです(インポートを含め、まったく関係のないものは省略しています)。順不同で、クラスは IntelliJ プロジェクト内の個別の .java ファイルにあります。ゲームは、新しいソルジャーがそのタイプを指定するように要求するポイントまで続きます (ユーザー入力を実行する関数は正常に機能し、技術的に同一のゲームの他の部分によって証明されているように入力を検証します)。

public class Boot {
    public static void main(String[] args) {
        Object[] games = new Object[] {};
        if (Lib.userConfirmPrompt("Start the game?") == true) {
            do {
                games[games.length] = new Game();
            }
            while (Lib.userConfirmPrompt("Do you want to play again?") == true);
        }
        System.exit(0);
    }
}

public class Game {
    public Object[] teams = new Object[] {};
    public Game() {
        for (int i = 0;i < settings.xbots + 1;i++) {
            teams[teams.length] = new Team(this);
        }
    }
}

public class Team {
    public Game game;
    public Army army;

    public Team(Game p) {
        game = p;
        army = new Army(this);
    }
}

public class Army {
    public Team team;
    public static Object[] soldiers = new Object[] {};

    public Army(Team p) {
        team = p;
        for (int i = 0;i < team.game.settings.xsoldiers;i++) {
            soldiers[soldiers.length] = new Soldier(this);
        }
    }
}

public class Soldier {
    private Army army;
    public int sight;
    public int range;
    public int distance;
    public int damage;

    public Soldier(Army p) {
        army = p;
        int type = Lib.userTxtIntOptionsPrompt(Data.isoldiertypes);
        // HERE is where it crashes, type is assigned and valid but the array access fails
        sight = Data.isoldierspecs[type][0];
        range = Data.isoldierspecs[type][1];
        distance = Data.isoldierspecs[type][2];
        damage = Data.isoldierspecs[type][3];
    }
}

public class Data {
    public static List isoldiertypes = Arrays.asList("Scout","Private","Machinegunner","Grenadier");
    public static int[][] isoldierspecs = {
        {6,1,6,40},
        {5,2,5,30},
        {5,3,4,40},
        {4,4,3,60}
    };
}

public class Lib {
    private static Scanner input = new Scanner(System.in);

    // output
    // default: 1 query string to print
    public static void outBase(String query) {
        System.out.print(query);
    }

    public static void outStd(String query) {
        outBase(query + "\n");
    }
    // end of output

    // input
    // default: 1 query string to print,
    //          query and input are in-line (exception: userConfirmPrompt prints query block-wise and default instruction in-line before input),
    //          keeps user hostage until valid input is given (exception: userPrompt returns blindly)
    public static String userPrompt(String query) {
        outBase(query);
        return input.nextLine();
    }

    public static String userTxtPrompt(String query) {
        String menuinput = null;
        do {
            if (menuinput != null) {
                userHostage();
            }
            menuinput = userPrompt(query);
        } while (menuinput.length() == 0);
        return menuinput;
    }

    public static int userIntPrompt(String query) {
        String menuinput = null;
        do {
            if (menuinput != null) {
                userHostage();
            }
            menuinput = userTxtPrompt(query);
        } while(menuinput.matches("^-?\\d+$") == false);
        return new Integer(menuinput);
    }
    // end of input

    // options input
    // default: takes a List of options as argument,
    //          prints an enumerated list of these options string-wise,
    //          prompts for a numeral selection of the desired option and returns the number if valid
    public static int userTxtIntOptionsPrompt(List options) {
        int choice = 0;
        Boolean chosen = false;
        do {
            if (chosen == true) {
                userHostage();
            } else {
                chosen = true;
            }
            chosen = true;
            for (int i = 0;i < options.size() - 2;i++) {
                outStd((i + 1) + ") " + options.get(i) + ",");
            }
            outStd((options.size() - 1) + ") " + options.get(options.size() - 2) + "\nand " + options.size() + ") " + options.get(options.size() - 1) + ".");
            choice = userIntPrompt("Enter the number of the option you'd like to select: ") - 1;
        } while(choice < 0 || choice >= options.size());
        return choice;
    }
    // end of options input

    // miscellaneous
    public static void userHostage() {
        outStd("Invalid operation. Please try again.");
    }
}
4

3 に答える 3

4

問題はあなたのArmyクラスにあります:

public static Object[] soldiers = new Object[] {};

という名前の空の (長さ == 0) 配列を初期化しますsoldiersが、後で以下にアクセスします。

soldiers[soldiers.length] = new Soldier(this);

これにより、障害が発生します。

定義により、soldiers.lengthは配列の範囲外です (範囲は from から0toであるためsoldiers.length-1)


これを克服するには、配列に十分なスペースを割り当てるか、代わりにsoldiers動的配列 ( ) を使用してください。usingにArrayList要素を追加することができ、それを埋める前に予想されるサイズを知る必要はありません。ArrayListArrayList.add()

于 2012-10-13T23:53:36.847 に答える
2

x は -1 より大きく 4 より小さい必要があります。

スタック トレースは Solder クラスについて言及していません。それは Army クラスのコンストラクターにあります。

とにかく、インデックスが範囲内にあることを知っているだけでは十分ではありません。プログラマーとして、そのインデックスで要素にアクセスしようとする前に、インデックスを検証する義務があります。

if(index > 0 && index < array.length) {
    //then only acess the element at index

問題は、配列の兵士のサイズが 0 であることです。

于 2012-10-13T23:24:28.050 に答える
0

この行int x = ...; // user inputは、ユーザーから何らかの方法で入力を取得し、それを使用して配列にアクセスしていることを意味します。この値が範囲内 (つまり、0 から 3 の間) であることを確認していますか? そうでない場合、これがテストが機能する理由である可能性があります。

編集:このようなものがあなたのためにそれを解決するかもしれません:

public class Army { 
    public Team team; 
    public Vector<Soldier> soldiers;

    public Army(Team p) { 
       soldiers = new Vector<Soldier>()
        team = p; 
        for (int i = 0;i < team.game.settings.xsoldiers;i++) { 
            soldiers.add(new Soldier(this));
        } 
    } 
}

他のコードから判断すると、この種のパターンはGameオブジェクトでも役立ちます。

于 2012-10-13T23:36:12.130 に答える