前言
在设计代码时常常会陷入纠结:
- 写一个通用方法,到底该不该加
static? - 工具类为什么要私有化构造器?
- 为什么 Controller、Service、Mapper 不设计成
static方法直接调用,非要注入一个对象? private final和private static final到底有什么本质区别?
很多时候我们只是死记硬背了规范,却忘了其背后的核心逻辑。这篇文章将从'对象'这个核心视角,把这些问题一次讲清楚。
一、回归本质:Static 到底是什么?
用最通俗的一句话来定义 static:
static属于类,不属于对象。
在 JVM 的内存模型和生命周期中,这意味着:
Static(静态)
- 不需要 new:随着类的加载而存在(在 JVM 启动或类首次被引用时)。
- 全类共享:无论你 new 多少个对象,static 数据只有一份。
- 没有 this:不依附于任何具体的实例。
Non-Static(非静态/实例)
- 必须 new:只有创建了对象,它才会在堆内存中分配空间。
- 依赖 this:它的执行必须依赖于当前对象的状态。
二、为什么工具类几乎全是 Static?
1. 工具类的特性
不管是 JDK 里的 Math.max() 还是 Hutool、Apache Commons 里的 StringUtils,它们都有共同的特点:
- 无状态:不需要保存数据。
- 纯函数:输入决定输出(例如:给一个 String,返回它的 MD5),多次调用结果一致。
- 不依赖外部对象。
既然不需要保存状态,new 一个对象出来就是对内存的浪费。因此,工具类天然适合 static。
2. 标准的工具类设计范式
一个成熟的 Java 工具类(如 HashUtil),应该长这样:
public final class HashUtil {
// 1. 私有化构造器,防止被 new
private HashUtil() {
throw new AssertionError("工具类不允许实例化");
}
// 2. 方法设为 static,直接通过类名调用
String {
result;
}
}

