static 是 Java 中一个非常核心且重要的关键字。static 意味着“属于类,而不是属于类的某个实例”。

当你在一个类成员(变量或方法)前使用 static 关键字时,你就告诉 JVM(Java 虚拟机):
这个成员不依赖于任何具体的对象实例,它被所有该类的对象共享,并且可以直接通过类名来访问,无需创建类的实例。
为了更好地理解,我们从 static 的几个主要用途入手。
静态变量 (Static Variables / Class Variables)
静态变量是属于整个类的变量,而不是属于某个特定对象的变量。

特点:
- 共享性:所有该类的对象共享同一个静态变量,一个对象修改了它的值,其他所有对象看到的都是修改后的值。
- 生命周期:静态变量的生命周期与类相同,它从类被加载到 JVM 内存中开始,直到类被卸载才消失,它的生命周期比任何对象实例都长。
- 内存位置:存储在方法区(Method Area)的静态区域中,而不是在堆(Heap)中每个对象的内存空间里。
示例: 假设我们要表示一个国家,每个国民(对象)都共享同一个国家名称。
public class Country {
// 非静态变量:每个国民都有自己的名字
private String citizenName;
// 静态变量:所有国民共享同一个国家名称
private static String countryName = "中国";
public Country(String citizenName) {
this.citizenName = citizenName;
}
public void displayInfo() {
System.out.println("公民姓名: " + this.citizenName);
System.out.println("所属国家: " + Country.countryName); // 通过类名访问
}
public static void main(String[] args) {
Country person1 = new Country("张三");
Country person2 = new Country("李四");
person1.displayInfo(); // 输出: 公民姓名: 张三, 所属国家: 中国
// 修改静态变量,会影响所有对象
Country.countryName = "中华人民共和国";
person2.displayInfo(); // 输出: 公民姓名: 李四, 所属国家: 中华人民共和国
}
}
在这个例子中,countryName 是静态的。person1 和 person2 都共享这个变量,当通过 Country.countryName 修改了它的值后,person2 再访问时,看到的就是新值。
什么时候使用静态变量?

- 当某个数据需要在所有实例之间共享时,
- 计数器:
public static int instanceCount = 0; - 配置信息:
public static final String DATABASE_URL = "jdbc:mysql://..."; - 常量:
public static final double PI = 3.14159;(注意:常量通常也用static final修饰)
- 计数器:
静态方法 (Static Methods / Class Methods)
静态方法是属于类的方法,而不是属于对象的方法。
特点:
- 不依赖对象状态:静态方法不能直接访问类的实例变量(非静态变量)和实例方法,因为它不依赖于任何具体的对象实例,而实例变量是依附于对象的。
- 访问限制:它只能访问静态变量和其他静态方法。
- 调用方式:通过类名直接调用,
Math.sqrt(4)。
示例:
Math 类是 static 方法的一个经典例子,你不需要创建一个 Math 对象来计算平方根,直接用 Math.sqrt() 即可。
public class Calculator {
// 静态方法:不依赖于任何计算器实例
public static int add(int a, int b) {
return a + b;
}
// 非静态方法:依赖于一个具体的计算器实例
public int multiply(int a, int b) {
// 假设这个计算器有内存功能
int memory = a * b;
System.out.println("计算结果已存入内存: " + memory);
return memory;
}
public static void main(String[] args) {
// 调用静态方法,通过类名
int sum = Calculator.add(10, 20);
System.out.println("和为: " + sum);
// 调用非静态方法,必须先创建对象
Calculator myCalc = new Calculator();
int product = myCalc.multiply(5, 6);
System.out.println("积为: " + product);
}
}
什么时候使用静态方法?
- 当方法不依赖于对象的状态(即不使用任何实例变量)时。
- 当工具类的方法,如
Math,Arrays,Collections等,它们提供的是一些通用的、与特定对象无关的功能。 - 作为程序的入口点
public static void main(String[] args)。
静态代码块 (Static Initialization Block)
静态代码块是一段在类加载时执行的代码块,用于初始化静态变量。
特点:
- 执行时机:当 JVM 第一次加载该类时执行,并且只执行一次。
- 执行顺序:在类的构造函数(
constructor)之前执行。 - 用途:通常用于初始化复杂的静态变量,例如加载配置文件、建立数据库连接池等。
示例:
public class DatabaseConnection {
private static Connection connection;
// 静态代码块
static {
System.out.println("正在加载驱动程序并建立数据库连接...");
try {
// Class.forName() 用于加载 JDBC 驱动
Class.forName("com.mysql.jdbc.Driver");
// 这里简化了连接的创建过程
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
System.out.println("数据库连接成功!");
} catch (Exception e) {
System.err.println("数据库连接失败!");
e.printStackTrace();
}
}
public static Connection getConnection() {
return connection;
}
}
当你的程序第一次使用 DatabaseConnection 类时,static 代码块会自动执行,完成数据库的初始化工作。
静态内部类 (Static Nested Class)
内部类(嵌套类)是定义在另一个类内部的类,如果内部类被声明为 static,它就变成了静态内部类。
特点:
- 独立性:静态内部类不持有对外部类对象的引用,这意味着你可以不创建外部类的实例,直接创建静态内部类的实例。
- 访问权限:它可以访问外部类的所有静态成员(变量和方法),但不能直接访问外部类的实例成员。
示例:
public class OuterClass {
private static String staticOuterField = "外部类的静态字段";
private String instanceOuterField = "外部类的实例字段";
// 静态内部类
public static static InnerClass {
// 静态内部类可以访问外部类的静态成员
public void display() {
System.out.println(staticOuterField);
// 下面这行会编译错误,因为无法访问外部类的实例成员
// System.out.println(instanceOuterField);
}
}
// 非静态内部类(成员内部类)
public class InnerClass {
// 非静态内部类可以访问外部类的所有成员
public void display() {
System.out.println(staticOuterField);
System.out.println(instanceOuterField);
}
}
}
使用场景: 当一个内部类只与外部类的静态部分相关联,并且不需要访问外部类的实例状态时,就应该使用静态内部类,这在设计模式(如 Builder 模式)中很常见。
总结与最佳实践
| 用法 | 关键点 | 何时使用 |
|---|---|---|
| 静态变量 | 所有对象共享,生命周期与类相同 | 当数据需要在所有实例间共享时,如计数器、常量。 |
| 静态方法 | 不依赖对象实例,不能访问实例变量 | 当方法提供通用功能,不操作对象状态时,如工具类方法。 |
| 静态代码块 | 类加载时执行一次,用于静态初始化 | 初始化静态变量,尤其是需要复杂逻辑(如加载配置、建立连接)。 |
| 静态内部类 | 不持有外部类引用,可独立存在 | 当内部类逻辑与外部类静态部分相关,且不依赖外部类实例时。 |
最佳实践与注意事项:
- 优先使用非静态:如果一个成员(变量或方法)依赖于对象的状态,那么它就应该是非静态的,只有在确实需要“共享”或“不依赖实例”时才使用
static。 - 避免可变静态状态:可变的静态变量(如
public static int counter)在多线程环境下是危险的,因为它会成为共享资源,容易引发线程安全问题,如果必须使用,要确保线程安全(例如使用synchronized或Atomic类)。 - 不要滥用
static:过度使用static会让你的程序变得难以测试和维护,因为它使得代码之间的耦合度变高,并且隐藏了对象之间的依赖关系,遵循“面向对象”的设计原则,优先考虑对象和它们之间的交互。 static与final:static final通常用来定义常量。static表示它属于类,final表示它的值一旦初始化就不能再改变。public static final int MAX_VALUE = 100;。
