为什么这段代码抛出一个ArrayIndexOutOfBoundsException?

时间:2011-09-15 00:01:52

标签: java arrays

以下是代码:

public class Deck {

    private Card[] cards;

    public Deck() {
        cards = new Card[52];
        String[] ranks = {"ace","two","three","four","five","six","seven","eight","nine","ten","jack","queen","king"};
        String[] suits = {"hearts","diamonds","clubs","spades"};
        for(int i = 0; i < suits.length; i++) {
            for(int n = 0; n < ranks.length; n++) {
                cards[cards.length] = new Card(ranks[i],suits[n]);
            }
        }
    }
}

正如您所看到的,这循环通过两个给定的数组并为每个组合生成一张卡片。共有13个排名×4个套装= 52张牌。我预计在第52次迭代时,cards.length将是51,但编译器说

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 52
    at com.cards.Deck.<init>(Deck.java:14)

为什么?

4 个答案:

答案 0 :(得分:2)

cards[cards.length]

因为您正在尝试使用不存在的索引。 cards.length为52,您的数组为0 - 51。

怀疑你试图将每张卡插入该阵列,这意味着你需要另一个计数器;)

int cardIndex = 0;
for(int i = 0; i < suits.length; i++) {
    for(int n = 0; n < ranks.length; n++, cardIndex++) {
        cards[cardIndex] = new Card(ranks[n],suits[i]);
    }
}

编辑:我没有抓到的是其他人提到的内容 - 你还在Card构造函数中切换了排名/套装的计数器 - 修正了它。

答案 1 :(得分:2)

问题是cards.length不是数组中使用的元素总数;无论你到目前为止存储在数组中的是什么,它都是数组中元素的总数。因此,只要执行内部循环,这将尝试访问数组的第52个元素,从而导致您看到的异常。

要解决此问题,请考虑存储一个计数器,该计数器将跟踪下一个免费索引,或者使用一些简单的数学计算来得出卡应该从其套装和值中进入的位置。例如,因为在外部循环的每次迭代中,您将向数组写入ranks.length元素,在迭代(in上)您将写入数组索引i * ranks.length + n 。使用它,您可以将内循环重写为

    // Careful... still buggy!
    for(int i = 0; i < suits.length; i++) {
        for(int n = 0; n < ranks.length; n++) {
            cards[i * ranks.length + n] = new Card(ranks[i],suits[n]);
        }
    }

此外,请注意您对阵列的访问是错误的。现在,你正在写

new Card(ranks[i],suits[n]);

但是,i范围超过套装,而不是值。正确的代码是

new Card(ranks[n],suits[i]);

这给出了最终的实施:

    for(int i = 0; i < suits.length; i++) {
        for(int n = 0; n < ranks.length; n++) {
            cards[i * ranks.length + n] = new Card(ranks[n],suits[i]);
        }
    }

但更一般地说,不要使用数组的.length字段来跟踪有多少使用过的元素。你需要单独存储它。或者,考虑使用ArrayList,它包装数组并为您跟踪。

希望这有帮助!

答案 2 :(得分:0)

交换排名等级和套装的索引变量。 (不要用手掌损坏头部。)

答案 3 :(得分:0)

使用重命名的变量来考虑它:

for(int SUIT = 0; SUIT < suits.length; SUIT++) {
    for(int RANK = 0; RANK < ranks.length; RANK++) {
        cards[cards.length] = new Card(ranks[SUIT],suits[RANK]);
    }
}

使用in并不总是最好的。 (我会使用sr。)

另外,请考虑:

Card[] cards = new Card[X];
cards[X] // will never be "in bounds", indices from [0, X-1]

快乐的编码。