static成员属于类而非对象,类加载时初始化一次并存于方法区(JDK8+在堆中Class对象尾部),故所有实例共享;static方法无this,不可访问非静态成员;静态代码块与变量按源码顺序执行且仅一次。

static 修饰的成员不属于对象,属于类本身,且只在类加载时初始化一次。它不是“写法糖”,而是直接改变内存布局和访问逻辑的关键字——理解这点,才能避开多数误用。
为什么 static 变量能被所有对象共享?
因为 JVM 在类加载阶段(ClassLoader 加载 .class 文件时),就把 static 成员存入方法区(JDK 8+ 后实际位于堆中的 Class 对象尾部),而非每个对象的堆空间里。
- 多个
new User()实例,共用同一份User.onlineNumber,改一个,全部看到变化 - 即使没创建任何对象,
User.onlineNumber已存在、可读写(如在main方法中直接访问) - 若误用
user1.onlineNumber = 999修改,本质仍是修改类级别的那一份,不是给user1单独赋值
static 方法里为什么不能用 this 或调用非静态成员?
因为 static 方法在类加载时就进入方法区,不依赖对象实例;而 this 指向当前对象,非静态成员变量/方法又绑定在堆中某个具体对象上——二者根本不在同一生命周期和作用域。
- 编译器会直接报错:
non-static variable name cannot be referenced from a static context - 想在
static方法中访问实例数据?必须显式传入对象引用,例如printUser(User u) -
工具类(如
Arrays.sort())全用static是合理的:它不操作任何“某一个对象”的状态,只做通用计算
静态代码块和静态变量初始化顺序怎么记?
一句话:**按源码从上到下执行,且只执行一次**。这是 JVM 规范保证的,比构造器更早触发,适合做类级资源预热。
立即学习“Java免费学习笔记(深入)”;
public class Config {
public static String DB_URL;
static {
System.out.println("1. 静态代码块开始");
DB_URL = "jdbc:mysql://localhost:3306/test";
System.out.println("2. 静态代码块结束");
}
public static final int MAX_RETRY = 3; // 编译期常量,先于静态块初始化
}
- 静态变量默认值(如
int为0,String为null)在类加载初期就赋予 - 显式赋值(
public static int x = 5;)和静态代码块,按文本顺序执行 - 别在静态块里调用尚未声明的静态变量(会得到默认值,不是你预期的“已赋值”结果)
最容易被忽略的是:static 不是“全局变量”的 Java 版替代品——它仍受类加载器隔离、访问控制符(private / protected)约束,且无法序列化到对象流中。用之前,先问自己一句:这个数据,真的需要跨所有实例、甚至跨类加载器共享吗?










