很抱歉,如果由于我遗漏了一些明显的东西而在某个地方得到了解答,但我现在一直在谷歌搜索这几天似乎没有任何意义。我有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.");
}
}
答案 0 :(得分:4)
问题出在您的Army
班级:
public static Object[] soldiers = new Object[] {};
您初始化一个名为soldiers
的空(长度== 0)数组,但稍后您将访问:
soldiers[soldiers.length] = new Soldier(this);
这会导致失败。
根据定义,soldiers.length
超出了数组的范围(因为绑定是从0
到soldiers.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
对象中也很有用。