You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归实现随机抽唯一卡牌时出现java.lang.StackOverflowError求助

问题分析与解决方案

原代码的核心问题

  1. Deck初始化错误:
    初始化deck时,你把同一个Integer[] deckSet对象重复添加了13次,导致deck里所有元素都是同一个数组的引用。一旦修改其中任意位置的数值,所有deck元素都会同步变化,很快所有卡牌标记都会被置为0,后续调用cardGenerator时永远抽不到有效卡牌,触发无限递归,最终导致StackOverflowError。

  2. 递归逻辑的缺陷:
    即使修复了初始化问题,递归方式也不稳定——当剩余卡牌数量较少时,重复抽到已抽取卡牌的概率会越来越高,递归深度急剧增加,依然可能触发栈溢出。


修复方案一:修正原逻辑(非递归实现)

先修复deck的初始化问题,同时把递归改成循环,避免栈溢出:

import java.util.ArrayList;
import java.util.Random;

public class App {
    static ArrayList<Integer[]> deck = new ArrayList<>();
    static ArrayList<Integer[]> dealer = new ArrayList<>();
    static Random random = new Random(); // 复用Random实例,避免重复创建

    static Integer[] cardGenerator() {
        while (true) {
            Integer num = random.nextInt(13);
            Integer shape = random.nextInt(4);
            Integer[] deckSet = deck.get(num);
            if (deckSet[shape] == 1) {
                deckSet[shape] = 0;
                // 数组是引用类型,修改后直接生效,无需调用deck.set
                return new Integer[]{num, shape};
            }
            // 抽不到有效牌就继续循环,直到抽到为止
        }
    }

    public static void main(String[] args) {
        // 每次循环新建数组,避免引用复用
        for (int i = 0; i < 13; i++) {
            deck.add(new Integer[]{1, 1, 1, 1});
        }
        for (int i = 0; i < 5; i++) {
            dealer.add(cardGenerator());
        }
        // 打印验证结果
        for (Integer[] card : dealer) {
            System.out.println("卡牌数字:" + card[0] + ",花色:" + card[1]);
        }
    }
}

更优方案二:洗牌法(推荐)

直接生成完整的52张卡牌列表,打乱顺序后取前5张,逻辑简洁高效,完全避免重复抽取问题:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class App {
    static List<Integer[]> dealer = new ArrayList<>();

    public static void main(String[] args) {
        // 生成全部52张卡牌
        List<Integer[]> fullDeck = new ArrayList<>();
        for (int num = 0; num < 13; num++) {
            for (int shape = 0; shape < 4; shape++) {
                fullDeck.add(new Integer[]{num, shape});
            }
        }
        // 洗牌打乱顺序
        Collections.shuffle(fullDeck);
        // 取前5张给dealer
        dealer.addAll(fullDeck.subList(0, 5));
        
        // 打印验证结果
        for (Integer[] card : dealer) {
            System.out.println("卡牌数字:" + card[0] + ",花色:" + card[1]);
        }
    }
}

这个方案无需维护已抽取卡牌的标记,通过洗牌直接保证随机性和唯一性,代码更简洁,性能也更稳定。

内容的提问来源于stack exchange,提问作者Lawrance

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:05:34