static 关键字作用
面试官问:"static 关键字有什么作用?"
候选人小魏答:"static 修饰的成员属于类,不属于实例。"
面试官点点头,又问:"static 变量在内存中放在哪里?"
小魏说:"堆?"
面试官:"static 方法能被子类重写吗?"
小魏说:"不能...吧?"
面试官追问:"为什么 static 方法不能被重写?"
小魏答不上来。
【面试官心理】 这道题看似简单,但能说出"静态方法没有多态"、"属于类而非实例"、"在方法区/元空间"三个核心点的候选人不多。追问 static 重写问题,是测试候选人对 Java 多态机制的理解。
一、static 修饰变量 🔴
1.1 类变量 vs 实例变量
1.2 内存位置
- 静态变量:存储在方法区/元空间(JDK 8+)
- 实例变量:存储在堆中,随对象一起分配
💡
JDK 8 将永久代(PermGen)移除,静态变量从"方法区"移到了"堆"中(但仍然受类加载器管理)。这是 JDK 7 到 JDK 8 的重要变化。
二、static 修饰方法 🔴
2.1 静态方法的特性
2.2 静态方法的限制
为什么 static 方法不能被重写?
- 重写(Override)需要运行时动态分派,基于对象的实际类型
- 静态方法属于类,在编译时就确定了调用版本(基于声明类型)
- 子类的"static 方法"是隐藏(hiding)父类的方法,不是重写
2.3 静态方法的使用原则
三、static 修饰代码块 🔴
3.1 静态代码块
执行顺序:按代码顺序执行,只在类第一次加载时执行一次。
3.2 静态代码块的执行时机
输出:
四、static 修饰内部类 🔴
五、常见面试陷阱 🔴
5.1 static 变量线程安全问题
⚠️
static 变量在多线程环境下是不安全的。多个线程同时修改同一个 static 变量,会产生竞态条件。如果需要线程安全,使用 AtomicInteger 或加锁。
5.2 静态变量导致的内存泄漏
静态集合持有对象引用 → 对象永远不会被 GC → 内存泄漏。
5.3 static 不能使用的场景
原因:static 方法和 static 变量属于类,不属于实例,而 this/super 是实例相关的概念。
六、追问升级
面试官:"main 方法为什么是 static 的?"
面试官:"静态内部类和静态变量,谁先加载?"