Java中的static都能用来修饰什么?
☕ Java 中的 static 能修饰什么?
static 是 Java 里的“反对象”修饰符,凡是被它标记的成员,就脱离了具体的对象实例,变成了类级别的共有财产。面试时别只背概念,我会分 5 类讲清楚,并附上容易忽略的细节。
1️⃣ 静态变量(类变量)—— 所有实例共享¶
-
特点:内存中只存储一份,被所有实例共享。适合记录全局状态(如在线人数、配置参数)。
-
加载时机:类加载时分配内存并初始化(非 final 的静态变量在
<clinit>方法里赋值)。 -
访问方式:推荐
类名.变量名,虽然用实例也能访问,但会引发警告。 -
注意:实例变量每个对象一份,静态变量整个类一份,别混用。
2️⃣ 静态方法(类方法)—— 不依赖对象即可调用¶
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}
// 调用:MathUtils.add(3,5)
- 特点:
- 直接通过类名调用,不需要
new对象。 -
只能访问静态变量和静态方法,不能直接访问实例变量/方法(因为没有
this)。 -
应用:工具类方法(
Math.max、Collections.sort)、工厂方法。 -
注意:静态方法不能被重写(但可以在子类中“隐藏”同名方法)。
3️⃣ 静态代码块 —— 类加载时执行,只一次¶
-
作用:用于初始化复杂的静态变量,或在类加载时做一次性工作(如加载本地库)。
-
执行顺序:如果类中有多个静态块,按代码顺序依次执行。父类的静态块优先于子类。
-
对比实例代码块:实例块在每次创建对象时执行,静态块只执行一次。
4️⃣ 静态内部类 —— 不依赖外部类实例¶
public class Outer {
static class StaticInner {
void print() { System.out.println("静态内部类"); }
}
}
// 创建:new Outer.StaticInner();
- 特点:
- 可以直接实例化,不需要先创建外部类对象。
-
只能访问外部类的静态成员(因为不持有外部实例引用)。
-
优势:普通非静态内部类会隐式持有外部类引用,容易造成内存泄漏;静态内部类更安全、更独立。
-
典型应用:
HashMap的Node、建造者模式中的 Builder。
5️⃣ 静态导入 —— 直接使用类里的静态成员,不加类名¶
- 注意:不要滥用,否则代码可读性变差,别人不知道
PI是哪里来的。一般只用在测试框架(如Assert.*)或频繁使用的常量。
🆕 Java 8 起:接口中的静态方法¶
public interface MyInterface {
static void staticMethod() {
System.out.println("接口的静态方法");
}
}
// 调用:MyInterface.staticMethod();
- 这是
static的扩展用法,把工具方法直接定义在接口里,避免额外的工具类。
⚠️ 容易被问到的陷阱¶
-
静态方法不能重写,但子类可以定义同名同参数的方法,这叫做隐藏,调用时具体执行哪个取决于引用类型(不是对象类型)。
-
静态变量是类级别的,但线程不安全,多线程并发修改需加
volatile或同步。 -
static和final组合是常量,编译期会内联,需要特别注意版本兼容(如public static final int MAX = 100;,若修改值,所有依赖类都要重新编译)。 -
静态上下文没有
this,所以不能用super关键字,也不能访问非静态内部类。