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

Java方法变量传递问题:牌组抽牌程序重复抽牌故障排查

问题与解决方案

问题描述

我实现了一个从牌组随机抽取卡牌并防止重复抽取的类方法,但该方法失效,原因是迭代值无法在方法调用间持续传递。请问是否可以避免方法中的变量被销毁?以下是相关代码:

Deck类代码

public class Deck
{
   // Array for the deck of cards
   private String[] DeckOfCards =
   { " 2 of spades ", " 3 of spades ", " 4 of spades ", " 5 of spades ", " 6 of spades ", " 7 of spades         ", " 8 of spades ", " 9 of spades ", " 10 of spades ", " Jack of spades ", " Queen of spades ",
     " King of Spades ", " Ace of spades ", " 2 of clubs ", " 3 of clubs ", " 4 of clubs ", " 5 of        
     clubs ", " 6 of clubs ", " 7 of clubs ", " 8 of clubs ", " 9 of clubs ", " 10 of clubs ", 
     " Jack of clubs ", " Queen of clubs ", " King of Clubs ", " Ace of clubs ", " 2 of diamonds ",
     " 3 of diamonds ", " 4 of diamonds ", " 5 of diamonds ", " 6 of diamonds ", " 7 of diamonds ",
     " 8 of diamonds ", " 9 of diamonds ", " 10 of diamonds ", " Jack of diamonds ", 
     " Queen of     diamonds ", " King of Diamonds ", " Ace of diamonds ", " 2 of hearts ", 
     " 3 of hearts ", " 4 of hearts ", " 5 of hearts ", " 6 of hearts ", " 7 of hearts ",
     " 8 of hearts ", " 9 of hearts ", " 10 of hearts ", " Jack of hearts ", " Queen of hearts ",
     " King of Hearts ", " Ace of hearts " };

   // Declaring other variables
   int[] alreadyDrawnCards = new int[53];
   int drawnCard;
   int i = 0;
   int j = 0;

   /**
    *  method used to draw cards
    */
   protected int draw()
   {       

      drawnCard = (int)(Math.random() * 53);

      while(j < i)
      {
         if(drawnCard == alreadyDrawnCards[j])
         {

            drawnCard = (int)(Math.random() * 53);
            j = -1;         
         }

         j++;
      }

      if(i < 53) 
      {
         alreadyDrawnCards[i] = drawnCard; // add drawn card to drawn cards
         i++;
      }

      System.out.println("The" + DeckOfCards[drawnCard] + "was drawn from the deck");

      return drawnCard;
   }
}

调用代码

public class BlackjackGameSimulator
{

   public static void main(String[] args)
   {
      Deck BlackJackDeck = new Deck();
      BlackJackDeck.draw();

   }
}

问题分析与解决

核心问题

你误解了变量销毁的问题:类成员变量i、alreadyDrawnCards、j都会随着Deck实例的存在而保留,不会被销毁。真正导致方法失效的是**j作为类成员变量,每次调用draw()后没有重置为0**,导致后续抽牌时循环逻辑混乱。

比如第一次调用draw()后,j的值会走到i的位置(比如i=1时j=1),第二次调用时j从1开始,跳过了对alreadyDrawnCards[0]的检查,就可能抽到重复卡牌。

修复步骤

  1. 将临时循环变量j移到方法内部
    把j的声明放到draw()方法里,每次调用时重新初始化为0,这样每次抽牌的循环都会从头检查已抽卡牌:

    protected int draw()
    {       
        int j = 0; // 移到方法内,每次调用重置
        drawnCard = (int)(Math.random() * 53);
    
        while(j < i)
        {
            if(drawnCard == alreadyDrawnCards[j])
            {
                drawnCard = (int)(Math.random() * 53);
                j = -1;         
            }
            j++;
        }
    
        if(i < 53) 
        {
            alreadyDrawnCards[i] = drawnCard;
            i++;
        }
    
        System.out.println("The" + DeckOfCards[drawnCard] + "was drawn from the deck");
        return drawnCard;
    }
    
  2. 优化抽牌逻辑(更高效的方案)
    当前的重复检测方式效率很低,每次抽牌都要遍历已抽数组。更合理的方式是初始化时洗牌,然后按顺序发牌,完全避免重复检测:

    import java.util.Random;
    
    public class Deck
    {
        private String[] deckOfCards =
        { " 2 of spades ", " 3 of spades ", " 4 of spades ", " 5 of spades ", " 6 of spades ", " 7 of spades ", 
          " 8 of spades ", " 9 of spades ", " 10 of spades ", " Jack of spades ", " Queen of spades ",
          " King of Spades ", " Ace of spades ", " 2 of clubs ", " 3 of clubs ", " 4 of clubs ", " 5 of clubs ", 
          " 6 of clubs ", " 7 of clubs ", " 8 of clubs ", " 9 of clubs ", " 10 of clubs ", 
          " Jack of clubs ", " Queen of clubs ", " King of Clubs ", " Ace of clubs ", " 2 of diamonds ",
          " 3 of diamonds ", " 4 of diamonds ", " 5 of diamonds ", " 6 of diamonds ", " 7 of diamonds ",
          " 8 of diamonds ", " 9 of diamonds ", " 10 of diamonds ", " Jack of diamonds ", 
          " Queen of diamonds ", " King of Diamonds ", " Ace of diamonds ", " 2 of hearts ", 
          " 3 of hearts ", " 4 of hearts ", " 5 of hearts ", " 6 of hearts ", " 7 of hearts ",
          " 8 of hearts ", " 9 of hearts ", " 10 of hearts ", " Jack of hearts ", " Queen of hearts ",
          " King of Hearts ", " Ace of hearts " };
    
        private int currentCardIndex = 0;
    
        // 构造方法里洗牌
        public Deck() {
            Random random = new Random();
            //  Fisher-Yates洗牌算法
            for (int k = deckOfCards.length - 1; k > 0; k--) {
                int swapIndex = random.nextInt(k + 1);
                String temp = deckOfCards[k];
                deckOfCards[k] = deckOfCards[swapIndex];
                deckOfCards[swapIndex] = temp;
            }
        }
    
        protected String draw() {
            if (currentCardIndex >= deckOfCards.length) {
                System.out.println("牌组已经抽完了");
                return null;
            }
            String drawnCard = deckOfCards[currentCardIndex++];
            System.out.println("抽到了:" + drawnCard);
            return drawnCard;
        }
    }
    

    这个方案不仅避免了重复问题,代码更简洁,效率也更高。

总结

  • 类成员变量不会随方法调用销毁,你的问题是错误地将临时循环变量设为成员变量导致状态混乱。
  • 把临时变量移到方法内部初始化即可解决原有逻辑问题;推荐使用洗牌法实现抽牌,更符合真实场景且高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 00:14:54