Java:数组中的索引存在,ArrayIndexOutOfBoundsException:0

标签 java windows arrays indexing

抱歉,如果由于我遗漏了一些明显的东西而在某个地方得到了回答,但我已经用谷歌搜索了好几天了,但它似乎没有任何意义。我在 Javascript 方面有 3 年的经验,现在正在学习 Java,所以我并不落后于任何事物的基本概念。

我为此使用了 IntelliJ,但它没有指出问题所在。我的类之间的通信(访问权限和实例化)很好,代码语法和变量类型也很好,所以我真的不知道它是什么。

我有一个数据类,它只保存供其他类使用的“只读”数据。

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) Boot包含main方法并实例化一个新的Game

2) 游戏实例化 x 个团队

3) 每个Team实例化一个Army

4) 每个陆军实例化 x 个士兵

类的每个实例都设置为实例化类的一个属性(例如,公共(public)陆军;以及团队构造函数中的陆军实例)。它本质上是级联的构造函数实例化后续类并将它们分配为其属性。

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.");
    }
}

最佳答案

问题出在您的 Army 类中:

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

您初始化了一个名为soldiers 的空(长度== 0)数组,但稍后您访问:

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

这会导致失败。

根据定义,soldiers.length 超出了数组的边界(因为边界是从 0soldiers.length-1)


要克服它 - 确保在数组 soldiers 中分配足够的空间或使用动态数组 ( ArrayList) 代替。您可以使用 ArrayList.add() 将元素附加到 ArrayList ,并且在填充之前不需要知道预期的大小。

关于Java:数组中的索引存在,ArrayIndexOutOfBoundsException:0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12877866/

相关文章:

arrays - TypeScript 中带有对象的数组的类型定义

c - 哪种排序算法对 c 中具有唯一元素的结构数组快速

java - ConcurrentHashMap.put V.S. ConcurrentHashMap.replace

java - 无法使用autocmd设置的gcc在MacVim中编译java

java - Gradle 中的多个依赖项版本

c# - 在 64 位处理器上为 3 Point 结构分配了多少字节?

java - 逐行读取文本文件并将对象存储在数组中

windows - Atom 菜单丢失。我如何重新启用

windows - 生成卸载命令的启动脚本

c++ - DLL加载和系统镜像空间