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

时间:2012-10-13 23:17:40

标签: java windows arrays indexing

很抱歉,如果由于我遗漏了一些明显的东西而在某个地方得到了解答,但我现在一直在谷歌搜索这几天似乎没有任何意义。我有3年的Javascript经验,现在正在进入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)Boot包含main方法并实例化一个新游戏

2)游戏实例化x团队

3)每个团队实例化一支军队

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

每个类的实例都被设置为实例化类的属性(公共陆军;以及Team构造函数中的Army实例化)。它本质上是一组构造函数实例化后续类并将它们指定为它们的属性。

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

3 个答案:

答案 0 :(得分:4)

问题出在您的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,并且在填写之前无需知道预期的大小。

答案 1 :(得分:2)

x应大于-1且小于4.

stacktrace没有提到Solder类,它在陆军类的结构中。

任何方式,只知道索引应该在一个范围内是不够的。作为程序员,您有责任在尝试访问该索引处的元素之前验证索引。

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

问题是阵列士兵的大小为0。

答案 2 :(得分: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对象中也很有用。