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 数组(全部通过调试输出语句确认)。然而,当它尝试设置 range 的值时(然后并且只有那时,在那个确切的点),我得到“索引超出范围”错误。

有人可以告诉我尝试读取数组时出了什么问题吗?或者我是否正确地说这真的很奇怪,我需要发布整个代码?

注意:一个小的新测试还表明,如果我将代码更改为首先从数组中输出手动选择的值,然后设置范围的值,控制台会打印错误语句(并退出程序)并通过打印手动选择的值,但分配值然后要求输出范围只会引发错误......这完全没有意义!

编辑:我已经编辑了上面的代码。在我的代码中,名为 Test 的类称为 Soldier(我正在制作基于文本的游戏......)。下面是堆栈跟踪,如果没有完整代码(很长)有什么好处。我的程序的基本结构是这样的:

1)Boot包含main方法并实例化一个新的Game

2) 游戏实例化 x Teams

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

4) 每支军队实例化 x 个士兵

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

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或使用动态数组 ( ArrayList)。您可以将元素附加到ArrayListusing ArrayList.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 回答