Java中静态变量在不同类加载器下互不共享,本质是每个加载器加载的同名类被视为不同类,各自拥有独立的静态变量副本、方法区空间和静态代码块执行过程。

Java 中静态变量在不同类加载器下不是“值不一致”,而是根本不存在共享关系——每个类加载器加载的同名类,其静态变量是完全独立的两份内存副本,互不可见、互不影响。
静态变量属于类,而类属于类加载器
JVM 规范明确:类的唯一性由「全限定类名 + 定义它的 ClassLoader 实例」共同决定。哪怕两个类加载器加载的是同一份字节码(比如都从同一个 JAR 里读取 com.example.Counter),它们在 JVM 中就是两个不同的类,各自拥有:
- 独立的方法区空间(元空间)
- 独立的静态变量存储区域
- 独立的静态代码块执行时机(各触发一次)
- 彼此无法强制类型转换,instanceof 判断返回 false
常见误判场景与实际表现
你以为改了 static 变量,其他地方应该同步?其实只是改了“某一个加载器视角下的那一份”:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- Web 应用中热部署或插件机制:Tomcat 的 WebAppClassLoader 加载业务类,而 SharedClassLoader 加载公共库。若两者都加载了 Config 类,Config.VERSION = "v2" 只影响前者加载的那个版本
- 自定义类加载器绕过委派:比如重写 loadClass 且未调用 super.loadClass,导致本该由 AppClassLoader 加载的类被新加载器重复加载,静态计数器就变成两套独立计数
- Thread.currentThread().getContextClassLoader() 被显式传入 Class.forName(className, true, cl):一旦 cl 和当前类所在加载器不一致,就可能触发二次加载,静态字段也就分裂
怎么验证是不是发生了类加载器分裂?
运行时可直接比对 Class 对象身份:
立即学习“Java免费学习笔记(深入)”;
- System.out.println(Counter.class.getClassLoader()) —— 看当前类由谁加载
- System.out.println(Counter.class == otherCounterClass) —— 若为 false,说明不是同一个类实例
- System.identityHashCode(Counter.class.getClassLoader()) —— 比较加载器实例是否相同
真正需要跨加载器共享时,别依赖 static
static 变量天然是类加载器局部的。要实现跨加载器状态共享,必须跳出类级别:
- 用 ConcurrentHashMap 做 JVM 全局缓存,key 设计为 className + "@" + System.identityHashCode(classLoader)
- 把配置值存在 System.getProperty() 或启动参数里,所有加载器都能读
- 高频/分布式场景下,改用 Redis、数据库或配置中心(如 Nacos)替代内存 static 字段
- 避免在静态块中调用 getClass().getClassLoader() 获取加载器——它返回的是“定义该类”的加载器,未必是你想要的

















