static 关键字的作用?

2025年 阅读约 7 分钟 面试指南 · Java面试

深入解析Java中static关键字的作用,从基本用法到类加载机制,分初级、中级、高级三个层次全面讲解。

一句话总结

static 属于类而非实例,在类加载时初始化,所有实例共享。可修饰变量/方法/代码块/内部类。静态内部类不持有外部类引用(避免内存泄漏),静态方法不能重写只能隐藏(静态分派看引用类型)。初始化顺序:父类静态 → 子类静态,同级别按代码顺序。

初级理解

static 表示"静态的",被 static 修饰的成员属于类而非实例,在类加载时初始化,所有实例共享。

static 可以修饰:

1. 静态变量(类变量):所有实例共享,通过类名直接访问

2. 静态方法:属于类,不能访问非静态成员,不能使用 this/super

3. 静态代码块:类加载时执行一次,用于初始化静态变量

4. 静态内部类:不依赖外部类实例,可以直接创建

public class Counter { private static int count = 0; // 静态变量,所有实例共享 private String name; static { // 静态代码块,类加载时执行一次 System.out.println("类初始化"); } public Counter(String name) { this.name = name; count++; // 每创建一个实例,count 加 1 } public static int getCount() { // 静态方法 return count; // return name; // 编译错误!不能访问非静态变量 } static class Builder { // 静态内部类 public void build() { System.out.println("building..."); } } }

中级深入

静态内部类 vs 非静态内部类:

对比静态内部类非静态内部类
依赖不依赖外部类实例必须通过外部类实例创建
访问权限只能访问外部类静态成员可以访问外部类所有成员
内存不持有外部类引用持有外部类引用(可能内存泄漏)
典型应用Builder 模式、工具类迭代器、事件监听器

静态导入(JDK 5):通过 import static 可以直接使用类的静态成员,无需类名前缀。

import static java.lang.Math.*; import static java.lang.System.out; double r = sqrt(pow(x, 2) + pow(y, 2)); // 无需 Math. out.println(r); // 无需 System.

高级拓展

static 与类加载时机:静态变量和静态代码块在类的初始化阶段执行。类加载分为:加载 → 验证 → 准备 → 解析 → 初始化。静态变量在准备阶段赋默认值(0/null),在初始化阶段赋代码中指定的值。

静态变量的初始化顺序:按照代码中的出现顺序依次执行。父类的静态变量先于子类初始化。

class Parent { static { System.out.println("1. Parent 静态块"); } } class Child extends Parent { static { System.out.println("2. Child 静态块"); } public static void main(String[] args) { System.out.println("3. main 方法"); } } // 输出:1 → 2 → 3

静态方法不能被重写:子类可以定义与父类同名的静态方法,但这不是重写(Override),而是隐藏(Hide)。调用哪个方法取决于引用类型而非实际类型。

class Parent { static void hello() { System.out.println("Parent"); } } class Child extends Parent { static void hello() { System.out.println("Child"); } } Parent p = new Child(); p.hello(); // 输出 "Parent"(静态分派,看引用类型)
面试加分项:能说出静态内部类不持有外部类引用(避免内存泄漏)和静态分派机制,说明你对 JVM 有深入理解。

实战场景

场景:单例模式中的静态内部类

// 静态内部类实现单例(推荐,线程安全 + 懒加载) public class Singleton { private Singleton() {} private static class Holder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return Holder.INSTANCE; // 首次访问 Holder 时才加载 } } // 优点:利用类加载机制保证线程安全,同时实现懒加载

场景:静态变量导致的内存问题

// 反例:静态集合持有对象引用,导致无法 GC public class DataCache { private static Map<String, Object> cache = new HashMap<>(); public static void put(String key, Object val) { cache.put(key, val); // 永远不会被回收! } } // 正例:使用 WeakHashMap 或定期清理 private static Map<String, WeakReference<Object>> cache = new HashMap<>();

面试模拟

Q:静态方法和实例方法的区别?

A:1) 静态方法属于类,通过类名调用;实例方法属于对象,通过实例调用;2) 静态方法不能访问实例变量和实例方法,不能使用 this/super;3) 静态方法不能被子类重写,只能隐藏;4) 静态方法在类加载时分配,实例方法在创建对象时分配。

Q:静态内部类和非静态内部类的区别?

A:1) 静态内部类不依赖外部类实例,可直接 new;非静态内部类必须先有外部类实例;2) 静态内部类只能访问外部类静态成员;非静态内部类可访问所有成员;3) 静态内部类不持有外部类引用,不会导致内存泄漏;4) 静态内部类常用于 Builder 模式,非静态内部类常用于迭代器。