0

0

Java中Hand类实例共享同一列表的深层原因与正确实现方案

心靈之曲

心靈之曲

发布时间:2026-01-01 13:02:02

|

951人浏览过

|

来源于php中文网

原创

Java中Hand类实例共享同一列表的深层原因与正确实现方案

本文详解java对象引用传递导致多个hand实例意外共享同一张牌列表的问题,通过修正构造函数、避免外部传入可变集合、改用局部变量计算手牌值,彻底解决手牌数据污染问题。

在Java中,对象是通过引用传递的——当你将同一个 List 实例传入多个 Hand2 构造函数时,所有 Hand2 对象内部的 hand 字段实际上指向内存中的同一个 ArrayList 对象。因此,对任一 Hand2 实例调用 addCard(),本质上都是向该共享列表追加元素,最终两个手牌显示相同内容、计算出相同点数也就不足为奇了。

根本问题在于原始设计违反了面向对象的封装原则:
✅ 正确做法:每个 Hand2 实例应自主管理其专属牌列表
❌ 错误做法:依赖外部传入并共享可变集合(如 new ArrayList()),使实例间产生隐式耦合。

以下是重构后的健壮实现:

public class Hand2 {
    private final List<Cards> hand; // 使用final确保引用不可变

    public Hand2() {
        this.hand = new ArrayList<>(); // 每个实例创建独立列表
    }

    public Cards addCard(Deck deck) {
        Cards drawn = deck.dealCard();
        hand.add(drawn);
        return drawn; // 返回抽到的牌,便于调试或逻辑扩展
    }

    public int getHandValue() {
        int total = 0; // 局部变量,每次调用重新计算,避免状态残留
        for (Cards card : hand) {
            total += card.getValue();
        }
        return total;
    }

    @Override
    public String toString() {
        return "Hand: " + hand;
    }
}

同时,测试代码也需同步更新,不再手动创建并复用同一列表

Zyro AI Image Upscaler
Zyro AI Image Upscaler

Zyro出品的AI图片放大工具

下载
public static void main(String[] args) {
    Deck deck = new Deck();
    deck.shuffle();

    Hand2 player1 = new Hand2(); // 各自拥有独立内部列表
    Hand2 player2 = new Hand2();

    player1.addCard(deck);
    player2.addCard(deck);
    player2.addCard(deck);

    System.out.println("Player 1: " + player1); // Hand: [Ace of Spades]
    System.out.println("Player 2: " + player2); // Hand: [Two of Hearts, King of Clubs]
    System.out.println("Player 1 value: " + player1.getHandValue()); // 11
    System.out.println("Player 2 value: " + player2.getHandValue()); // 12
}

⚠️ 关键注意事项:

立即学习Java免费学习笔记(深入)”;

  • 永远不要通过构造函数接收可变集合(如 List, Map)并直接赋值给成员变量,除非明确需要共享语义(极少见);
  • 若必须支持外部初始化,应使用防御性拷贝:this.hand = new ArrayList(hand);
  • handValue 等计算型状态不应作为字段缓存(除非有性能优化需求且保证同步更新),否则易因未及时刷新导致逻辑错误;
  • 重写 toString() 时务必添加 @Override 注解,避免因方法签名错误导致未生效。

通过以上改进,每个玩家的手牌真正实现了数据隔离,为后续扩展多玩家、AI决策、胜负判定等复杂逻辑打下坚实基础。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

58

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

63

2025.11.27

java值传递和引用传递有什么区别
java值传递和引用传递有什么区别

java值传递和引用传递的区别:1、基本数据类型的传递;2、对象的传递;3、修改引用指向的情况。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

109

2024.02.23

go语言引用传递
go语言引用传递

本专题整合了go语言引用传递机制,想了解更多相关内容,请阅读专题下面的文章。

175

2025.06.26

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

47

2025.11.27

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11万人学习

Java 教程
Java 教程

共578课时 | 80万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号