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

Java中如何在两个相似类间共享对象?以游戏玩家共享牌组为例

嘿,这个问题问到点子上了!看你用了ArrayList,应该是用Java开发游戏吧?其实你现在的场景里,根本不用特意去“返回修改后的cardList”——因为Java里对象是按引用传递的,只要Human和Computer拿到的是同一个Deck(或者cardList)的引用,它们操作的就是同一个实例,修改会自动同步的!

下面给你两种可行的实现思路,推荐第一种,更符合面向对象的设计原则:

方案1:封装Deck类,共享Deck实例(最推荐)

别直接把cardList暴露给玩家类,而是把抽牌、洗牌这些和牌堆相关的逻辑都封装在Deck类里,然后让Human和Computer共享同一个Deck实例就行。这样既保证了数据的一致性,又避免了外部类直接操作内部列表的风险。

示例代码大概是这样的:

// Deck类:封装牌堆的所有逻辑
public class Deck {
    private ArrayList<Card> cardList;

    public Deck() {
        cardList = new ArrayList<>();
        // 这里初始化所有卡牌,比如循环添加52张牌
        for (String suit : new String[]{"红桃", "方块", "黑桃", "梅花"}) {
            for (int num = 1; num <= 13; num++) {
                cardList.add(new Card(suit, num));
            }
        }
    }

    // 抽牌方法:内部负责修改cardList,返回抽到的牌
    public Card drawCard() {
        if (cardList.isEmpty()) {
            throw new IllegalStateException("牌堆已经空啦!");
        }
        // 从牌堆顶部抽牌(你也可以改成随机抽,只要在Deck里改就行)
        return cardList.remove(0);
    }

    // 可以加洗牌方法,同样封装在Deck里
    public void shuffle() {
        Collections.shuffle(cardList);
    }
}

// Human类:依赖共享的Deck实例
public class Human {
    private ArrayList<Card> hand;
    private Deck sharedDeck;

    public Human(Deck deck) {
        this.sharedDeck = deck;
        this.hand = new ArrayList<>();
    }

    public void takeCard() {
        Card drawnCard = sharedDeck.drawCard();
        hand.add(drawnCard);
        System.out.println("人类玩家抽到了:" + drawnCard);
    }
}

// Computer类:和Human逻辑一致,共享同一个Deck
public class Computer {
    private ArrayList<Card> hand;
    private Deck sharedDeck;

    public Computer(Deck deck) {
        this.sharedDeck = deck;
        this.hand = new ArrayList<>();
    }

    public void takeCard() {
        Card drawnCard = sharedDeck.drawCard();
        hand.add(drawnCard);
        System.out.println("电脑玩家抽到了:" + drawnCard);
    }
}

// 游戏启动时的代码
public class Game {
    public static void main(String[] args) {
        Deck gameDeck = new Deck();
        gameDeck.shuffle(); // 先洗牌

        Human player1 = new Human(gameDeck);
        Computer aiPlayer = new Computer(gameDeck);

        // 双方抽牌,操作的是同一个Deck里的cardList
        player1.takeCard();
        aiPlayer.takeCard();
    }
}

这种方式下,不管是人类玩家还是电脑玩家抽牌,都是调用同一个Deck实例的drawCard方法,cardList的修改会自动同步给所有持有该Deck引用的对象,完全不需要手动返回或者传递修改后的列表。

方案2:直接共享cardList(不推荐,但能生效)

如果你一定要直接传递cardList,那要记住:Java中ArrayList是对象,当你把它作为构造函数参数传给Human和Computer时,两个类拿到的是同一个列表的引用。也就是说,只要其中一方修改了列表(比如移除元素),另一方访问这个列表时看到的就是修改后的版本。

比如:

// Human类里的抽牌逻辑
public void drawCard(ArrayList<Card> cardList) {
    Card card = cardList.remove(0);
    this.hand.add(card);
}

当你把同一个cardList传给Human和Computer后,不管哪一方调用这个方法,都会直接修改原列表,另一方再访问时就能看到最新状态。

但这种方式不推荐,因为它把Deck的内部数据暴露给了外部类,违反了封装原则——以后如果要改抽牌规则(比如从牌堆底部抽,或者添加弃牌堆逻辑),你得修改所有玩家类的代码,维护成本很高。

额外注意:线程安全问题

如果你的游戏是多线程的(比如人类玩家和电脑玩家在不同线程同时抽牌),直接操作共享的cardList会有并发冲突的风险。这时候可以给Deck的drawCard方法加上synchronized修饰符,保证同一时间只有一个线程能修改牌堆:

public synchronized Card drawCard() {
    // 原逻辑不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:29:58