static变量属于类而非实例,所有对象共享同一份内存,类加载时初始化且全程存在;可通过类名直接访问,常用于计数器、配置项等,但需注意线程安全及不可访问非静态成员。

static 关键字声明的类变量(也叫静态变量)属于类本身,而不是某个具体对象,因此所有实例共享同一份内存空间。只要类被加载进 JVM,static 变量就已存在,且只初始化一次。修改它,所有实例看到的都是最新值。
类变量 vs 实例变量:关键区别
普通成员变量(不加 static)每个对象独有一份;而用 static 修饰的变量只有一份,被整个类的所有实例共同持有:
- 实例变量随 new 出现而分配内存,随对象销毁可能被回收
- 静态变量在类加载时分配内存,在整个程序运行期间一直存在
- 可通过类名直接访问(如
Counter.count),无需创建对象
典型使用场景:计数器、配置项、缓存池
比如统计创建了多少个对象:
class Counter {
static int count = 0; // 所有实例共享
Counter() {
count++;
}
}
每次 new 一个 Counter,count 就加 1。无论你创建 10 个还是 100 个实例,它们读到的都是同一个 count 值。
其他常见用途包括:
- 全局开关标志(如
static boolean DEBUG = true) - 数据库连接池、线程池等资源管理器(单例 + static 结合)
- 常量定义(配合 final,如
static final String API_URL = "https://...")
注意线程安全问题
多个线程同时读写 static 变量时,可能出现数据不一致。例如两个线程几乎同时执行 count++,可能都读到旧值再各自加 1,结果只加了一次。
解决方法有:
- 用
synchronized块或方法保护临界区 - 使用原子类(如
AtomicInteger)替代基本类型 - 避免在 static 变量上做复合操作(如先读再写),尽量用不可变设计
不能访问非静态成员
static 方法或静态代码块中,不能直接访问 this、非 static 成员变量或非 static 方法,因为此时还没有任何实例存在。如果真需要,必须显式创建对象或传入引用。
反例:
static void printName() {
System.out.println(name); // 编译错误!name 是实例变量
}
正解是把 name 设为 static,或让 printName 接收一个对象参数。










