Java中实现货币类加法操作的指南与实践

Java中实现货币类加法操作的指南与实践

本文详细指导如何在java中为一个自定义的`money`类实现一个健壮的`add`方法,以实现两个货币对象的加法运算。重点讲解了如何正确处理美分(cents)的溢出逻辑,确保货币金额始终保持有效表示,并讨论了在方法设计中关于对象可变性的重要考量。

在面向对象编程中,处理货币金额是一项常见任务。一个设计良好的Money类不仅需要存储美元和美分,还应提供可靠的算术运算方法。本文将以一个Java Money类为例,详细阐述如何实现其add方法,确保货币加法运算的准确性和健壮性。

1. Money类基础结构概述

一个基本的Money类通常包含两个私有字段:dollars(美元)和cents(美分)。关键在于,cents字段应始终保持在一个有效范围内,通常是[0, 99]。这意味着每当美分累加到100或更多时,就需要将溢出的部分转换为美元。

import java.util.Objects; // 用于hashCode和equals// import java.util.Scanner; // 如果需要从Scanner构造,可以引入class Money {    private int cents;    private int dollars;    // 默认构造函数    public Money() {        this(0, 0);    }    // 带参数的构造函数,并进行规范化    public Money(int dollars, int cents) {        this.dollars = dollars;        this.cents = cents;        normalize(); // 确保初始值符合规范    }    // 辅助方法:规范化美分值,确保其在[0, 99]范围内    private void normalize() {        if (this.cents >= 100) {            this.dollars += this.cents / 100; // 将溢出的美分转换为美元            this.cents %= 100; // 保留剩余的美分        }        // 如果需要支持负数金额,这里还需要处理 this.cents < 0 的情况        // 例如:        // while (this.cents < 0) {        //     this.cents += 100;        //     this.dollars--;        // }    }    // 重写toString方法,用于友好的字符串表示    @Override    public String toString() {        return "$" + dollars + "." + String.format("%02d", cents); // 格式化美分,确保总是两位数    }    // 重写equals方法,用于比较两个Money对象的值是否相等    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Money money = (Money) o;        return cents == money.cents && dollars == money.dollars;    }    // 重写hashCode方法,与equals方法同步,用于哈希集合等场景    @Override    public int hashCode() {        return Objects.hash(cents, dollars);    }    // 其他方法(例如从Scanner读取的构造函数,此处省略以保持焦点)    /*    public Money(Scanner sc) {        String token = sc.next();        int dot = token.indexOf(".");        this.cents = Integer.parseInt(token.substring(dot + 1));        this.dollars = Integer.parseInt(token.substring(1, dot));        normalize(); // 确保从输入解析的值也符合规范    }    */}

2. add方法的核心逻辑实现

add方法的目标是将另一个Money对象的值加到当前对象(接收者)上。实现这个方法需要考虑以下几个关键步骤:

2.1 空值(null)参数检查

在执行任何加法操作之前,必须检查传入的other对象是否为null。如果为null,尝试访问其字段会导致NullPointerException。通常,这种情况下可以选择抛出IllegalArgumentException或返回当前对象而不做任何修改。

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

2.2 基本加法运算

首先,将other对象的dollars和cents分别累加到当前对象的dollars和cents上。

2.3 美分溢出处理与规范化

这是实现货币加法最关键的一步。由于cents必须保持在[0, 99]的范围内,累加后如果this.cents达到或超过100,就需要进行规范化。这意味着将多余的美分转换为美元,并更新this.cents为剩余的美分。前面定义的normalize()辅助方法正是为此目的而设计。

稿定抠图 稿定抠图

AI自动消除图片背景

稿定抠图 76 查看详情 稿定抠图

2.4 返回值设计

在许多情况下,add方法被设计为修改当前对象(接收者)的状态,并返回对当前对象的引用(this),这使得方法可以链式调用。

结合以上步骤,add方法的实现如下:

// 接续Money类定义class Money {    // ... (现有字段、构造函数、toString、equals、hashCode和normalize方法) ...    /**     * 实现货币加法方法。     * 该方法会修改当前Money对象(接收者)的状态,并返回自身。     *     * @param other 另一个Money对象,其值将被加到当前对象上。     * @return 修改后的当前Money对象。     * @throws IllegalArgumentException 如果other参数为null。     */    public Money add(Money other) {        if (other == null) {            throw new IllegalArgumentException("Cannot add a null Money object.");        }        this.cents += other.cents;     // 累加美分        this.dollars += other.dollars; // 累加美元        normalize();                    // 规范化美分值        return this; // 返回当前对象    }}

3. 设计考量与注意事项

在实现Money类的算术运算时,有几个重要的设计决策和注意事项需要考虑。

3.1 对象的可变性 (Mutability)

上述add方法的实现使得Money对象是可变的(Mutable),即调用add方法会改变对象自身的内部状态。

优点: 性能上可能更高效,因为它避免了创建新对象的开销。缺点:线程安全问题: 在多线程环境中,如果多个线程同时修改同一个Money对象,可能会导致数据不一致。副作用: 方法调用会改变对象状态,可能导致难以追踪的副作用,尤其是在复杂系统中。不可预测性: 当一个Money对象被多个引用共享时,通过其中一个引用对其进行修改,会影响所有引用。

替代方案:实现不可变(Immutable)的add方法

为了避免可变性带来的问题,可以设计一个返回新Money对象的add方法,而不修改当前对象。这种方法被称为不可变操作。

// 接续Money类定义class Money {    // ... (现有字段、构造函数、toString、equals、hashCode和normalize方法) ...    /**     * 实现不可变货币加法方法。     * 该方法不会修改当前Money对象,而是返回一个包含加法结果的新Money对象。     *     * @param other 另一个Money对象,其值将被加到当前对象上。     * @return 一个新的Money对象,表示加法结果。     * @throws IllegalArgumentException 如果other参数为null。     */    public Money addImmutable(Money other) {        if (other == null) {            throw new IllegalArgumentException("Cannot add a null Money object.");        }        int resultDollars = this.dollars + other.dollars;        int resultCents = this.cents + other.cents;        // 规范化结果        resultDollars += resultCents / 100;        resultCents %= 100;        return new Money(resultDollars, resultCents); // 返回一个新的Money对象

以上就是Java中实现货币类加法操作的指南与实践的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1028553.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何拒绝Microsoft Teams调查
上一篇 2025年12月2日 02:08:20
如何在Win7系统中删除网络位置
下一篇 2025年12月2日 02:08:23

相关推荐

  • 获取物品名称并转换为字符串时出现乱码的解决方案

    获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案

    本文旨在解决在 Minecraft Spigot 插件开发中,获取玩家放置的物品名称并尝试将其转换为字符串时出现乱码的问题。通过分析问题原因,并提供正确的代码示例,帮助开发者避免类似错误,从而更有效地获取玩家名称。 在 Spigot 插件开发中,当玩家放置方块时,我们可能需要获取该方块对应的玩家名称…

    2026年9月25日 • 用户投稿
    100
  • Bukkit插件开发:正确处理物品显示名称与玩家识别

    Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别

    本文旨在解决Bukkit插件开发中,从BlockPlaceEvent获取物品显示名称并将其用于玩家识别时常见的“乱码”问题。我们将深入探讨Component对象与纯文本字符串的区别,并提供两种核心解决方案:直接获取放置方块的玩家名称,以及如何正确地将Component转换为纯文本字符串,以避免不必要…

    2026年9月25日 • 用户投稿
    300
  • sublime怎么折叠所有代码_sublime代码折叠快捷方法

    sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法

    Sublime Text 支持多种代码折叠快捷键,Windows/Linux 使用 Ctrl + Shift + [/] 折叠/展开代码块,Ctrl + K, Ctrl + 1 展开所有用 Ctrl + K, Ctrl + J,macOS 用户将 Ctrl 替换为 Command。 在 Sublim…

    2026年9月25日 • 用户投稿
    200
  • 解析音调调整指令:一个Java教程

    解析音调调整指令:一个Java教程解析音调调整指令:一个Java教程解析音调调整指令:一个Java教程解析音调调整指令:一个Java教程

    本文旨在提供一个清晰易懂的Java教程,用于解析包含音调调整指令的字符串。通过使用正则表达式,我们可以从复杂的输入字符串中提取乐器名称、调整方向和调整量。本教程将详细解释代码实现,并提供示例,帮助读者理解如何在Java中处理这类问题。 使用正则表达式解析音调调整指令 在音乐领域,音调的微调至关重要。…

    2026年9月25日 • 用户投稿
    100
  • Java字符串高级解析:使用正则表达式处理复杂指令模式

    Java字符串高级解析:使用正则表达式处理复杂指令模式Java字符串高级解析:使用正则表达式处理复杂指令模式Java字符串高级解析:使用正则表达式处理复杂指令模式Java字符串高级解析:使用正则表达式处理复杂指令模式

    本教程演示如何使用Java的java.util.regex包,通过正则表达式高效解析包含多条调音指令的复杂字符串。我们将学习构建匹配特定模式的正则表达式,并利用Pattern和Matcher类从输入字符串中准确提取乐器名称、调音方向和数值,从而将原始指令转换为清晰可读的输出格式。 1. 问题背景与挑…

    2026年9月25日 • 用户投稿
    100
  • Java中整数类型溢出行为详解:二进制补码与循环特性

    Java中整数类型溢出行为详解:二进制补码与循环特性Java中整数类型溢出行为详解:二进制补码与循环特性Java中整数类型溢出行为详解:二进制补码与循环特性Java中整数类型溢出行为详解:二进制补码与循环特性

    Java中原始整数类型在处理超出其范围的数值时,会遵循一种基于二进制补码的循环溢出机制。这意味着当正数溢出时会“回卷”为负数,反之亦然,如同数字在一个有限的圆环上循环。理解这一特性对于准确预测类型转换和算术运算结果至关重要。 计算机中的数值表示:位、字节与二进制 在计算机底层,所有数据都以二进制形式…

    2026年9月25日 • 用户投稿
    100
  • Java数据类型溢出:原理、预测与避免

    Java数据类型溢出:原理、预测与避免Java数据类型溢出:原理、预测与避免Java数据类型溢出:原理、预测与避免Java数据类型溢出:原理、预测与避免

    本文旨在深入解析Java中数据类型溢出的现象,阐述其背后的二进制补码原理,并提供预测溢出结果的方法。通过理解数据在计算机中的存储方式,以及溢出时数值的循环特性,开发者可以更好地掌握Java中的数据类型,避免潜在的错误。 数据在计算机中的存储:二进制补码 计算机底层使用二进制(bits)来表示所有数据…

    2026年9月25日 • 用户投稿
    100
  • Java中数据类型溢出的原理及预测方法

    Java中数据类型溢出的原理及预测方法Java中数据类型溢出的原理及预测方法Java中数据类型溢出的原理及预测方法Java中数据类型溢出的原理及预测方法

    本文旨在阐明Java中当数值超出所选数据类型范围时发生的溢出现象,并提供预测溢出结果的方法。文章将深入探讨计算机中数值的存储方式,特别是补码表示法,以及溢出时数值如何“环绕”的原理。通过理解这些概念,读者可以准确预测Java中数据类型溢出的结果。 理解计算机中的数值表示:补码 在计算机中,所有数据最…

    2026年9月25日 • 用户投稿
    200
  • 使用 DynamoDBMapper 进行条件更新操作

    使用 DynamoDBMapper 进行条件更新操作使用 DynamoDBMapper 进行条件更新操作使用 DynamoDBMapper 进行条件更新操作使用 DynamoDBMapper 进行条件更新操作

    本文将介绍如何利用 DynamoDBMapper 在 Java 中执行基于当前值的条件更新操作,特别是使用 “ADD” 操作来递减账户余额。虽然 DynamoDBMapper 默认不支持直接使用更新表达式,但通过配置 SaveBehavior,可以实现类似的效果。 Dynam…

    2026年9月25日 • 用户投稿
    100
  • 解决JavaFX应用导出为可运行JAR后FXMLLoader资源加载失败的问题

    解决JavaFX应用导出为可运行JAR后FXMLLoader资源加载失败的问题解决JavaFX应用导出为可运行JAR后FXMLLoader资源加载失败的问题解决JavaFX应用导出为可运行JAR后FXMLLoader资源加载失败的问题解决JavaFX应用导出为可运行JAR后FXMLLoader资源加载失败的问题

    本文旨在解决JavaFX应用在Eclipse中正常运行,但导出为可运行JAR包后,因FXMLLoader无法找到FXML资源文件而抛出IllegalStateException: Location is not set异常的问题。核心解决方案是调整FXMLLoader.setLocation()方法…

    2026年9月25日 • 用户投稿
    200
  • Java多态中成员变量是否具有动态绑定特性

    成员变量不具有动态绑定特性,其访问基于引用变量的声明类型而非实际对象类型。例如,当父类和子类存在同名成员变量时,通过父类引用访问该变量将获取父类中的值,即使实际对象是子类实例。这体现了静态绑定,即在编译期确定访问的变量。相比之下,实例方法支持动态绑定(后期绑定),在运行时根据对象的实际类型决定调用哪…

    2026年9月25日
    100
  • Java 中处理货币数据的正确方式

    Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式

    在 Java 应用程序中,尤其是在处理财务数据时,选择正确的数据类型至关重要。货币数据通常以特定的格式呈现,例如包含货币符号(如美元符号 $)和千位分隔符(如逗号 ,)。直接将这些数据映射到 DTO 类时,我们需要仔细考虑数据类型的选择,以避免潜在的精度损失和计算错误。 货币数据类型选择考量 常见的…

    2026年9月25日 • 用户投稿
    000
  • Java 中处理货币数据的最佳实践

    Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践

    本文旨在探讨在 Java 中处理货币数据的最佳实践。面对 JSON 数据中包含的货币值(例如 “$234,205,860″),直接使用 String 存储是一种选择,但可能并非最优。本文将深入分析各种数据类型在处理货币时的优劣,并推荐使用 BigDecimal 进行精确计算,…

    2026年9月25日 • 用户投稿
    000
  • Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制

    Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制

    本文深入探讨Java中向上转型、方法重载与可变参数(varargs)的交互机制。通过具体代码示例,详细解释了在向上转型场景下,为何编译器会基于引用变量的编译时类型来解析方法调用,即使子类存在看似更匹配的重载方法。核心在于方法重载是编译时决策,而可变参数在重载解析中具有较低的优先级。理解这些机制对于编…

    2026年9月25日 • 用户投稿
    000
  • Groovy编程:在HTTP请求头中传递授权令牌的实践指南

    Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南

    本教程详细介绍了如何在Groovy中通过HTTP请求头发送授权令牌,以实现对RESTful API的安全访问。针对用户在Groovy中模拟curl -H ‘Authorization: token …’命令时遇到的常见问题,本文提供了基于java.net.URL和…

    2026年9月25日 • 用户投稿
    900
  • uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置

    uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置

    1、可通过UC浏览器设置关闭自动播放:进入设置→网站管理→媒体自动播放,选择关闭;2、启用省流加速模式减少视频自动加载;3、使用隐私模式浏览限制脚本执行,阻止视频自动播放。 如果您在使用UC浏览器浏览网页时,遇到视频自动播放影响阅读体验的情况,可以通过调整浏览器设置来禁止此行为。自动播放功能通常由浏…

    2026年9月25日 • 用户投稿
    600
  • 通过索引访问 LinkedHashMap 的值

    通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值

    通过索引访问 LinkedHashMap 的值 本文将探讨如何比较两个 LinkedHashMap 中具有相同键的值,并提供一种有效的解决方案。LinkedHashMap 是一种可以保持插入顺序的 Map 实现,但它并不支持像 List 那样通过索引直接访问元素。因此,当我们需要比较两个 Linke…

    2026年9月25日 • 用户投稿
    1200
  • 通过索引获取 LinkedHashMap 的值?解决方案与最佳实践

    通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践

    本文旨在解决如何比较两个 LinkedHashMap 中具有相同键(chargeTypeName)的值的问题。由于 LinkedHashMap 本身不支持通过索引直接访问,文章将探讨如何利用流(Stream)和分组(Grouping)等技术,有效地找出两个 LinkedHashMap 中键相同的值对…

    2026年9月25日 • 用户投稿
    100
  • 使用 Jackson 进行复杂类的自定义反序列化

    使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化

    本文介绍了如何使用 Jackson 库对包含复杂嵌套类的 JSON 字符串进行自定义反序列化。通过 ObjectMapper 的 readValue 方法可以实现简单场景下的自动反序列化。针对需要定制化处理的场景,可以结合 ObjectMapper 和自定义反序列化器来实现更灵活的反序列化逻辑,并提…

    2026年9月25日 • 用户投稿
    1000
  • p5.js WebGL性能优化:首帧渲染耗时长的原因与对策

    p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策

    在使用p5.js的WEBGL渲染模式时,首次调用image()函数渲染图片或p5.Graphics对象通常会比后续调用耗时显著增加。这主要是因为第一次渲染时,p5.js需要将图像数据从CPU内存上传到GPU的纹理内存中,涉及内存分配和数据复制,这是一个相对耗时的过程。后续调用由于纹理已被缓存,可以直…

    2026年9月25日 • 用户投稿
    800

发表回复

登录后才能评论
关注微信