静态变量能被所有实例共享,根本原因在于它属于类而非对象,生命周期从类加载开始至程序结束,JDK 8+ 存于堆中 Class 对象末尾,仅一份副本且所有实例共用同一内存地址。

静态变量之所以能被所有实例共享,根本原因在于它的内存归属和生命周期——它不属于任何一个对象,而是属于类本身,随类加载而诞生,随程序结束而消亡。
存储位置:不在堆里,而在方法区(JDK 8+ 在堆中 class 对象内)
静态变量不随 new 出现而分配,也不随对象销毁而回收。它的存放位置取决于 JVM 版本:
- JDK 7 及以前:存于方法区的静态常量池,是类元数据的一部分
- JDK 8 开始:方法区被元空间(Metaspace)取代,静态变量实际存放在堆内存中 Class 对象的末尾,仍由该 Class 对象统一持有
无论哪种实现,本质一致:只有一个副本,且与具体对象无关。
共享机制:所有实例指向同一块内存地址
当你创建多个对象时,每个对象的实例变量(如 name、age)各自在堆中占独立空间;但静态变量(如 count、money)始终只有一份,所有对象读写操作都落在同一内存地址上:
- 修改 Counter.count,所有 Counter 实例下次读取都是新值
- 哪怕没有创建任何实例,也能通过 Counter.count 直接访问或赋值
- 不能通过 this 访问静态变量(this 指向实例,而静态变量不属于实例)
初始化时机:类加载阶段完成,早于任何对象创建
静态变量的初始化发生在类首次主动使用时(如第一次 new、调用静态方法、访问静态字段),此时 JVM 执行类加载、链接、初始化三步流程,静态变量被赋予初始值或执行静态代码块:
- 声明时直接赋值(static int count = 0;)→ 在准备阶段赋默认值,初始化阶段赋指定值
- 依赖静态代码块(static { count = initFromConfig(); })→ 在初始化阶段执行
- 不会因多次 new 而重复初始化,仅一次
访问规则:静态上下文只能访问静态成员
这是编译器强制的逻辑约束,源于生命周期不匹配:
- 静态方法/静态代码块运行时,可能尚无任何对象存在 → 无法确定 this 指向谁 → 不能访问非静态字段或方法
- 实例方法可以访问静态成员,因为静态成员始终存在,且可通过类名或隐式 this(编译器自动转为类名)访问
- 错误示例:static void printName() { System.out.println(name); } → 编译失败,name 是实例变量

















