final修饰类是最硬的继承拦截手段,编译期直接拒绝extends,JVM字节码层面不支持继承,IDE编辑时即标红,反射和字节码生成亦无法绕过。

用 final 修饰类,Java 编译器会直接拒绝任何 extends 尝试,这是最硬的继承拦截手段。
final 类声明后子类编译失败是确定行为
只要类被声明为 final,JVM 字节码层面就不会生成可被继承的类结构。哪怕子类只写个空壳,javac 也会报错:
error: cannot inherit from final class
class MySubClass extends String { }
这不是运行时检查,而是编译期强制约束。所有主流 IDE(IntelliJ、Eclipse)都会在编辑阶段标红提示。
-
final修饰的是类本身,和其中字段/方法是否final无关 - 匿名内部类不能继承
final类,Lambda 表达式也不能基于它构造函数式实例 - 反射也无法绕过:调用
Class.forName()加载没问题,但Unsafe.defineClass()或字节码生成库(如 ASM)若试图构造其子类,会在verify阶段失败
哪些类适合加 final?看是否满足“不可变契约”
不是所有工具类都要 final,关键看设计意图是否要求“行为封闭”。典型场景包括:
立即学习“Java免费学习笔记(深入)”;
- 值对象:如
String、LocalDateTime—— 继承会破坏不可变性假设 - 安全敏感类:如
java.security.MessageDigest的具体实现(如SHA256),防止被恶意子类篡改摘要逻辑 - 框架核心契约类:如 Spring 的
BeanFactory是接口,但它的默认实现DefaultListableBeanFactory并非final;而像org.springframework.util.Assert这类纯静态工具类加final是为防误继承(它甚至没构造器)
反例:ArrayList 不是 final,因为设计上允许用户扩展(如重写 add() 做日志);强行加 final 会破坏开闭原则。
final 类里还能用 protected 吗?能,但没意义
可以声明 protected 方法或字段,但编译器不会报错,因为语法合法。问题在于:没人能继承它,protected 的访问权限实际降级为包内可见(package-private)。
更隐蔽的问题是——如果你后期想移除 final,又忘了把 protected 改成 private,就可能意外暴露内部细节。所以建议:
- 如果类已定为
final,所有成员优先用private - 除非你明确需要同包其他类调用,才用
package-private(不写修饰符) - 避免写
protected,它在这里只是个“幻觉权限”
真正难的是判断“该不该 final”,而不是怎么写。很多人加 final 是怕别人乱继承,却忽略了自己写的类根本没提供可被合理重写的钩子(比如全是 private 方法),这时候 final 只是心理安慰。安全设计的核心,是厘清类的职责边界,而不是堆砌关键字。










