final是修饰符,表示不可变:修饰类则禁止继承(编译期报错),修饰方法则禁止重写,修饰变量则初始化后不可修改值或引用。

final 类:编译期直接拒绝 extends
声明为 final class A 后,任何 class B extends A 都会在编译阶段报错,错误信息类似 Cannot inherit from final 'A'。这不是运行时检查,JVM 根本不生成继承关系字节码。
常见误操作:
- 试图在子类中用
@Override注解修饰继承自 final 类的方法(根本不会编译通过,因为没子类) - 认为 final 类里的方法必须显式加
final(不需要,final 类天然无子类,所有实例方法都不可重写) - 把工具类(如只含静态方法的
StringUtils)设为非 final,导致别人意外继承并污染命名空间
适用场景:值对象(LocalDateTime)、安全敏感类(SecretKey)、已完全封装的 DTO。
final 方法:允许继承调用,但禁止 @Override
在非 final 类中声明 public final void doWork(),子类能正常调用 obj.doWork(),但一旦写 @Override public void doWork() 就会编译失败,提示 method does not override or implement a method from a supertype 或更直白的 cannot override final method。
注意几个关键点:
-
private方法不是靠final阻止重写——它连继承都不存在,谈不上重写;final只对public/protected实例方法生效 -
static方法被“隐藏”(hiding),不是重写;给 static 方法加final仅防止子类定义同名 static 方法,和实例方法的语义不同 - final 方法可以重载(overload),比如
doWork()和doWork(String s)共存完全合法
final 与测试、框架集成的隐性冲突
Mockito 3.x 默认无法 mock final 类或 final 方法,报错类似 Cannot mock/spy class ... because it is final。这不是设计缺陷,而是明确的限制。
解决方案取决于你控制权范围:
- 若你是类作者:除非强安全需求,否则避免对整类加
final;方法级final更可控 - 若你是使用者:升级到 Mockito 4+ 并启用 inline mock(需添加
mockito-inline依赖),但会带来额外开销和兼容风险 - Spring AOP 代理无法拦截 final 方法调用——CGLIB 代理会跳过 final 方法,JDK 动态代理则根本无法代理 final 类
final 不是银弹:该用在哪,不该用在哪
final 的核心价值是表达设计意图:这个类/方法的行为契约必须稳定。但它会立刻切断扩展路径。
容易被忽略的边界情况:
- 接口不能有
final实例方法(default方法可被重写,加final直接语法错误) - 构造方法不能加
final(编译报错),因为构造方法不参与继承机制 - 抽象类里不能有
final抽象方法(语义矛盾,抽象方法必须被实现,final 又禁止实现) - final 类可以继承其他类(只要父类不是 final),只是它自己不能再被继承
真正需要 final 的地方不多:不可变值类型、防篡改的安全逻辑、性能关键路径上需 JVM 内联的方法。其余多数时候,留出扩展余地比过早锁定更务实。

















