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

为何NumberFormat类的format方法会调用子类DecimalFormat的format方法?

解答:这是Java多态与模板方法模式的典型应用

这完全符合面向对象的设计逻辑,核心原因是**多态(运行时类型绑定)**以及Java格式化类库的模板方法设计:

1. currencyInstance的实际类型是DecimalFormat

你通过NumberFormat.getCurrencyInstance()(或同类方法)获取的currencyInstance,虽然声明类型是抽象父类NumberFormat,但运行时实际指向的是DecimalFormat的实例——NumberFormat作为抽象工厂类,负责返回具体的格式化实现子类(DecimalFormat是Java中处理数字/货币格式化的默认实现)。

2. final方法与可重写方法的分工

  • NumberFormat中的format(long number)是final方法,它的作用是提供统一的调用入口,保证核心流程不可被子类修改。这个方法内部并没有直接实现格式化逻辑,而是调用了另一个重载方法:
    public final String format(long number) {
        return format(number, new StringBuffer(),
                      DontCareFieldPosition.INSTANCE).toString();
    }
    
  • 被调用的format(long, StringBuffer, FieldPosition)是NumberFormat中定义的可重写方法(甚至是抽象方法),DecimalFormat作为子类重写了这个方法来实现具体的货币格式化逻辑。

3. 运行时的多态绑定

当JVM执行format(number, new StringBuffer(), DontCareFieldPosition.INSTANCE)时,会根据对象的实际运行时类型(也就是DecimalFormat)来查找对应的方法实现,因此会跳转到DecimalFormat中重写的版本,这就是你调试时看到的现象。

简化示例理解

用一个简单的代码片段模拟这个逻辑:

abstract class NumberFormat {
    public final String format(long number) {
        // 统一入口,调用子类实现的细节方法
        return format(number, new StringBuffer()).toString();
    }

    // 由子类实现具体逻辑
    protected abstract StringBuffer format(long number, StringBuffer result);
}

class DecimalFormat extends NumberFormat {
    @Override
    protected StringBuffer format(long number, StringBuffer result) {
        result.append("格式化后的数字:").append(number);
        return result;
    }
}

// 调用场景
public class Main {
    public static void main(String[] args) {
        NumberFormat currencyInstance = new DecimalFormat();
        currencyInstance.format(14000); // 实际执行DecimalFormat的format方法
    }
}

这种设计是模板方法模式的典型应用:父类用final方法固定整体流程,子类重写特定方法定制细节,既保证了流程的一致性,又具备灵活性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:25:33