static关键字
核心含义
static译为 "静态的",在 Java 中它的核心作用是:将类的成员(变量、方法、代码块、内部类)与类本身绑定,而非与类的实例(对象)绑定。
简单来说:
- 非静态成员:属于 "对象",每个对象有独立的一份,必须通过对象访问。
- 静态成员:属于 "类",整个程序运行期间只有一份副本,可直接通过类名访问,无需创建对象。
具体用法
静态变量(类变量)
被 static 修饰的变量称为类变量,归属类本身而非类的具体对象实例 ,由该类所有实例化的对象共享同一份内存副本,任意一个对象修改该值,所有对象访问到的都会是修改后的值。
静态变量在 JVM 加载类时(类加载阶段)完成初始化,存储于方法区,整个程序运行期间仅初始化一次,生命周期与类的生命周期绑定;可通过「类名.变量名」直接访问。
特点
- 用
static修饰的成员变量,称为静态变量 / 类变量。 - 存储在方法区(而非堆内存),类加载时初始化,生命周期与类一致。
- 所有对象共享同一份静态变量,修改一个对象的静态变量,会影响所有对象。
代码示例
java
public class Student {
// 非静态变量(实例变量):每个学生对象有独立的名字
private String name;
// 静态变量(类变量):所有学生共享同一个学校名称
public static String school = "北京大学";
// 构造方法
public Student(String name) {
this.name = name;
}
// 获取名字
public String getName() {
return name;
}
public static void main(String[] args) {
// 1. 直接通过类名访问静态变量(推荐)
System.out.println(Student.school); // 输出:北京大学
// 2. 创建对象访问(不推荐,易混淆)
Student s1 = new Student("张三");
Student s2 = new Student("李四");
System.out.println(s1.school); // 输出:北京大学
System.out.println(s2.school); // 输出:北京大学
// 3. 修改静态变量(所有对象都会受影响)
s1.school = "清华大学";
System.out.println(s2.school); // 输出:清华大学
System.out.println(Student.school); // 输出:清华大学
}
}

上述代码中name为非静态变量,对象s1、s2创建后在堆内存当中进行存储,且是对象私有的;
school被static修饰,是静态变量,存储在方法区中,我们在main方法中给school重新赋值为清华大学,所有对象的school变量都发生了改变。
常见使用场景
- 定义常量(配合
final:public static final double PI = 3.1415926;)。 - 统计类的实例数量(如
private static int count = 0;,构造方法中count++)。
静态方法(类方法)
被 static 关键字修饰的方法被规范称为静态方法(Static Method),也常称作类方法(Class Method),其核心本质是归属类的全局范畴,而非类实例化后的具体对象实例,是类的固有行为,不依赖任何对象的状态(属性)。
特点
- 用
static修饰的方法,称为静态方法 / 类方法。 - 静态方法属于类,可直接通过类名调用,无需创建对象。
- 核心限制 :静态方法中不能访问非静态成员(非静态变量、非静态方法),也不能使用
this/super关键字(因为this指向当前对象,而静态方法不依赖对象)。
代码示例
java
public class MathUtil {
// 静态方法:计算两数之和(工具类方法常用static)
public static int add(int a, int b) {
// 静态方法中不能访问非静态变量(如下行会报错)
// System.out.println(nonStaticVar);
return a + b;
}
// 非静态方法
public void printInfo() {
System.out.println("这是非静态方法");
// 非静态方法可以访问静态方法/变量(合法)
System.out.println(add(1, 2));
}
public static void main(String[] args) {
// 1. 直接通过类名调用静态方法(推荐)
int sum = MathUtil.add(3, 5);
System.out.println(sum); // 输出:8
// 2. 通过对象调用(不推荐)
MathUtil util = new MathUtil();
sum = util.add(4, 6);
System.out.println(sum); // 输出:10
// 3. 调用非静态方法(必须创建对象)
util.printInfo();
}
}
注意:在同一个类中访问本类的静态成员(方法 / 变量),可以省略 "类名." 的前缀。
所以System.out.println(add(1, 2));也能正常输出3

常见使用场景
- 工具类(如
java.lang.Math、java.util.Arrays中的所有方法都是静态的)。 - 工厂方法(创建对象的方法,如
Integer.valueOf())。 - 主方法
main()(必须是static,因为程序启动时还没有创建类的对象)。
静态代码块
被 static 关键字修饰的代码块称为静态代码块(Static Block),也叫静态初始化块,是 Java 中专门用于初始化类级静态成员(静态变量、静态资源)的特殊代码结构,其核心设计目的是为静态成员提供复杂的初始化逻辑。
特点
- 用
static {}包裹的代码块,称为静态代码块。 - 作用:初始化静态变量,或执行类加载时需要的一次性操作。
- 执行时机:类加载时(早于构造方法)执行,且只执行一次(无论创建多少对象,静态代码块仅执行一次)。
代码示例
java
public class StaticBlockDemo {
// 静态变量
public static int num;
// 静态代码块:初始化静态变量
static {
System.out.println("静态代码块执行");
num = 100;
// 可以执行复杂的初始化逻辑,如读取配置文件
}
// 构造方法
public StaticBlockDemo() {
System.out.println("构造方法执行");
}
// 构造代码块
{
System.out.println("构造代码块执行");
}
public static void main(String[] args) {
// 创建第一个对象:先执行静态代码块,再执行构造方法
StaticBlockDemo demo1 = new StaticBlockDemo();
System.out.println(demo1.num); // 输出:100
// 创建第二个对象:静态代码块不再执行,仅执行构造方法
StaticBlockDemo demo2 = new StaticBlockDemo();
System.out.println(demo2.num); // 输出:100
}
}
执行顺序
类加载时的执行顺序:静态变量声明/赋值 → 静态代码块 →main方法执行 →构造代码块({}) → 构造方法。
main方法本身是静态方法,属于类级别的成员,因此必须等类加载完成(静态代码块执行完毕)后才能执行;- 构造代码块和构造方法是对象级别的 ,只有在
main方法中执行new 类名()创建对象时才会触发,因此必然在main方法执行过程中(且在创建对象的那一行)才会执行,且晚于main方法的启动。 - 从输出结果可以看到,静态代码块只执行了一次,而构造代码块和构造方法每次对象创建都会执行
静态内部类
定义与特点
- 用
static修饰的内部类,称为静态内部类(也叫嵌套类)。 - 特点:
- 静态内部类属于外部类,而非外部类的对象。
- 可以直接创建静态内部类的对象,无需先创建外部类对象。
- 静态内部类中可以访问外部类的静态成员,但不能直接访问外部类的非静态成员(如需访问,需传入外部类对象)。
代码示例
java
public class OuterClass {
// 外部类静态变量
public static String outerStaticVar = "外部类静态变量";
// 外部类非静态变量
public String outerNonStaticVar = "外部类非静态变量";
// 静态内部类
public static class StaticInnerClass {
public void print() {
// 可以直接访问外部类的静态变量
System.out.println(outerStaticVar);
// 不能直接访问外部类的非静态变量(如下行会报错)
// System.out.println(outerNonStaticVar);
// 如需访问,需创建外部类对象
OuterClass outer = new OuterClass();
System.out.println(outer.outerNonStaticVar);
}
}
public static void main(String[] args) {
// 创建静态内部类对象(无需先创建外部类对象)
OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
inner.print();
}
}

static 的常见误区
- 误区 1 :认为静态成员可以被所有类访问。→ 错误:静态成员的访问权限仍受
public/private/protected修饰符限制(如private static变量仅能在本类访问)。 - 误区 2:静态方法中可以重写(Override)。→ 错误:静态方法属于类,不存在 "重写"(重写是针对对象的多态特性),子类的静态方法只是 "隐藏" 了父类的静态方法,而非重写。
- 误区 3 :静态变量线程安全。→ 错误:静态变量被所有线程共享,多线程环境下直接修改静态变量会导致线程安全问题(需加锁,如
synchronized)。
总结
static的核心是绑定到类,而非对象:静态成员属于类,仅一份副本,可通过类名直接访问;非静态成员属于对象,每个对象一份。- 静态方法的核心限制:不能访问非静态成员,不能用
this/super。 - 常见使用场景:工具类方法、常量定义、类加载时的初始化(静态代码块)、静态内部类(简化类结构)。
掌握 static 的关键是理解 "类级别的成员" 和 "对象级别的成员" 的区别,在实际开发中,合理使用 static 可以减少对象创建、提升性能,但过度使用(如滥用静态变量存储状态)会导致代码耦合度高、线程安全问题,需谨慎。
类的加载顺序
我们来看下面的代码:
java
// 父类
class Parent {
// 父类静态变量1
static int parentStaticVar = printNum("1.父类静态变量显式赋值");
// 父类静态代码块1
static {
printNum("2.父类静态代码块1");
}
// 父类静态代码块2
static {
printNum("3.父类静态代码块2");
}
// 父类实例变量1
int parentInstanceVar = printNum("5.父类实例变量显式赋值");
// 父类实例代码块
{
printNum("6.父类实例代码块");
}
// 父类构造方法
public Parent() {
printNum("7.父类构造方法");
}
// 辅助打印方法(静态)
public static int printNum(String msg) {
System.out.println(msg);
return 0; // 仅为赋值用,无实际意义
}
}
// 子类
class Child extends Parent {
// 子类静态变量1
static int childStaticVar = printNum("4.子类静态变量显式赋值");
// 子类静态代码块
static {
printNum("4.子类静态代码块"); // 注意:和静态变量按声明顺序,这里是第4步后
}
// 子类实例变量1
int childInstanceVar = printNum("8.子类实例变量显式赋值");
// 子类实例代码块
{
printNum("9.子类实例代码块");
}
// 子类构造方法
public Child() {
// 隐含super(),会先执行父类实例初始化
printNum("10.子类构造方法");
}
}
// 测试类
public class ClassLoadOrderTest {
public static void main(String[] args) {
System.out.println("=====第一次创建子类实例=====");
Child c1 = new Child();
System.out.println("\n=====第二次创建子类实例=====");
Child c2 = new Child();
}
}
输出:

类初始化阶段(仅执行一次)
① 父类静态变量显式赋值 → ② 父类静态代码块(按声明顺序)
→ ③ 子类静态变量显式赋值 → ④ 子类静态代码块(按声明顺序)
对象实例化阶段(每次new子类都执行)
⑤ 父类实例变量显式赋值 → ⑥ 父类实例代码块(按声明顺序)
→ ⑦ 父类构造方法
→ ⑧ 子类实例变量显式赋值 → ⑨ 子类实例代码块(按声明顺序)
→ ⑩ 子类构造方法
JVM 执行 main 方法的完整流程:
定位 main 方法所在的类;
初始化该类(执行其静态变量 / 静态代码块,若有父类则先初始化父类);
执行 main 方法;
main 方法执行过程中,若用到其他类,则初始化该类(执行其静态变量 / 静态代码块)。
所以需要注意的是静态资源属于 main 方法所在类则在 main() 前执行
详细解释:
阶段 1:加载入口类,执行 main 方法开头
JVM 启动后,首先加载 ClassLoadOrderTest 类(包含 main 方法的入口类),由于该类中无其他静态变量 / 静态代码块则直接执行 main 方法,输出第一次创建子类实例;
阶段 2:第一次创建 Child 实例触发类初始化与实例化
执行 new Child() 时,JVM 发现 Child 类未初始化,且 Child 继承自 Parent,因此先完成父类→子类的静态初始化,再执行父类→子类的实例化(静态资源是类级别的,父类是子类的基础,因此先初始化父类静态资源)。
父类 Parent 的静态初始化(仅执行 1 次):按代码书写顺序执行父类的静态资源(静态变量显式赋值 + 静态代码块);
子类 Child 的静态初始化(仅执行 1 次):父类静态初始化完成后,按代码书写顺序执行子类的静态资源(静态变量显式赋值 + 静态代码块);
父类 Parent 的实例化(子类构造隐含 super ()):子类静态初始化完成后,开始实例化 Child 对象,子类构造方法第一行隐含super()(调用父类无参构造),因此先执行父类的实例资源实例(变量显式赋值、实例代码块),按照代码书写的先后顺序执行;
子类 Child 的实例化:父类实例化完成后,执行子类的实例资源(实例变量显式赋值、实例代码块),按照代码书写的先后顺序执行;
阶段 3:第二次创建 Child 实例仅执行实例化
此时 Parent 和 Child 的静态初始化已完成,因此仅执行父类→子类的实例化。
