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

创建两个完全相同但独立的扑克牌组并同时从两组抽牌

解决两个独立扑克牌组的抽牌问题

嘿,我一眼就看出你大概率踩了静态变量的坑!你说创建两个Deck实例后,抽104次只拿到一个牌组的52张牌,另一个全是空,几乎可以肯定是你的Deck类里用来存牌的数组/列表被定义成了static——静态变量是属于类的,不是属于单个实例的,所以两个Deck对象其实共用同一堆牌,第一个抽完52张后,第二个自然就没牌可抽了。

下面给你一套完整的修正方案,从Deck类的正确实现,到测试类的写法,帮你搞定两个独立牌组的并排抽牌:

1. 正确实现独立的Deck类

首先要确保牌组的核心存储(比如cards列表)是实例变量,不是静态的。同时要实现完整的创建、洗牌、抽牌逻辑:

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

public class Deck {
    // 每个Deck实例都有自己的cards列表,绝对不要加static!
    private List<String> cards;

    public Deck() {
        initStandardDeck();
        shuffleDeck();
    }

    // 初始化52张标准扑克牌
    private void initStandardDeck() {
        cards = new ArrayList<>();
        String[] suits = {"♠", "♥", "♦", "♣"};
        String[] ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
        
        for (String suit : suits) {
            for (String rank : ranks) {
                cards.add(rank + suit);
            }
        }
    }

    // 洗牌逻辑
    public void shuffleDeck() {
        Collections.shuffle(cards);
    }

    // 抽牌:取出并移除最后一张牌,空牌组返回null(也可以抛出异常,按需调整)
    public String drawCard() {
        if (cards.isEmpty()) {
            return null;
        }
        // Java 9+用removeLast(),低版本可以用remove(cards.size()-1)
        return cards.removeLast();
    }

    // 可选:获取剩余牌数,方便调试
    public int getRemainingCards() {
        return cards.size();
    }
}

2. 测试类DeckDrawTest的正确写法

现在创建两个独立的Deck实例,循环抽104次,就能分别拿到两个牌组的所有牌了:

public class DeckDrawTest {
    public static void main(String[] args) {
        Deck deck1 = new Deck();
        Deck deck2 = new Deck();

        int totalDraws = 104;
        for (int i = 0; i < totalDraws; i++) {
            String cardFromDeck1 = deck1.drawCard();
            String cardFromDeck2 = deck2.drawCard();
            
            System.out.printf("第%d次抽牌:牌组1 = %s,牌组2 = %s%n", 
                i+1, 
                cardFromDeck1 != null ? cardFromDeck1 : "无牌", 
                cardFromDeck2 != null ? cardFromDeck2 : "无牌");
        }

        // 最后验证剩余牌数,应该都是0
        System.out.println("牌组1剩余牌数:" + deck1.getRemainingCards());
        System.out.println("牌组2剩余牌数:" + deck2.getRemainingCards());
    }
}

3. 如果需要复制现有牌组(比如复制一个完全相同的牌组)

如果你的需求是先创建一个牌组,然后复制出另一个初始状态完全一致的(比如牌的顺序、洗牌状态都相同),可以给Deck类加复制构造方法,或者实现Cloneable接口:

方案一:复制构造方法

在Deck类里添加:

// 复制构造方法,深拷贝传入的牌组的牌列表
public Deck(Deck otherDeck) {
    // 必须new一个新的ArrayList,避免两个牌组共享同一列表引用
    this.cards = new ArrayList<>(otherDeck.cards);
}

使用方式:

Deck originalDeck = new Deck();
Deck copiedDeck = new Deck(originalDeck); // 复制出完全相同的独立牌组

方案二:实现Cloneable接口

@Override
public Deck clone() {
    try {
        Deck clonedDeck = (Deck) super.clone();
        // 对引用类型成员做深拷贝
        clonedDeck.cards = new ArrayList<>(this.cards);
        return clonedDeck;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError(); // 不会触发,因为我们实现了Cloneable
    }
}

使用方式:

Deck originalDeck = new Deck();
Deck clonedDeck = originalDeck.clone();

关键注意点

  • 禁用静态变量存牌组:这是你之前遇到空值问题的核心原因,静态变量属于类,所有实例共享同一数据。
  • 深拷贝的必要性:复制牌组时一定要复制底层列表,不能直接赋值引用,否则两个牌组还是会互相影响。
  • 边界处理:抽牌时要检查牌组是否为空,避免抛出数组越界异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:48:17