讲解

到目前为止,字段和方法都属于具体的对象:每个 Person 各有自己的 name。static 修饰的成员则属于类本身,被该类的所有对象共享一份——不管 new 出一百个还是一个都没有,静态成员永远只有一份,通过「类名.成员」访问(对象也能点出来,但不推荐,容易误以为它属于对象)。典型用途是计数器:在构造方法里 count++,就能统计这个类一共造过多少个对象。

静态方法同理:不依赖任何对象的状态,Math.sqrt(16)、Arrays.sort(arr) 都是静态方法,直接用类名调用,不用先 new。main 方法必须是 static 的原因也在这里——程序启动时还没有任何对象,JVM 只能调用一个不需要对象的方法。反过来要记住静态方法的限制:里面没有 this,不能直接访问实例字段和实例方法,因为静态上下文里根本不存在「当前对象」。

静态常量 static final 是配置类数据的标准写法:public static final int MAX_SIZE = 100;,全大写命名,全局共享且不可改。另外类首次被加载时会执行静态代码块 static { ... },适合做一次性的初始化,日常用得不多,见到认识即可。判断「该不该用 static」的标准:这个成员描述的是「每个对象各自的状态」还是「这一类事物共享的事实/与对象无关的工具」——前者绝不能 static,后者就该 static。

示例

静态字段做实例计数器,所有对象共享同一份:

class Student {
    private static int count = 0;
    private final String name;

    public Student(String name) {
        this.name = name;
        count++;
    }

    public static int getCount() {
        return count;
    }

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("初始数量:" + Student.getCount());
        new Student("李明");
        new Student("王芳");
        Student s = new Student("张伟");
        System.out.println(s.getName() + " 报到后,总数:" + Student.getCount());
    }
}

静态工具方法与静态常量:

class Circle {
    public static final double PI = 3.141592653589793;

    public static double area(double radius) {
        return PI * radius * radius;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("半径 2 的圆面积:" + Circle.area(2));
        System.out.println("Math.max(3, 9) = " + Math.max(3, 9));
        System.out.println("Math.sqrt(16) = " + Math.sqrt(16));
    }
}

常见坑

  • 在静态方法里访问实例成员:编译报错「无法从静态上下文引用非静态变量」。想访问实例数据,要么把方法改成实例方法,要么把对象作为参数传进来。
  • 把每个对象都该有的状态写成 static:static String name 会让所有实例共享一个名字,后建的对象把前者的覆盖掉。static 字段是「类级别」的,别拿它存个体数据。
  • 过度使用静态工具类:全是静态方法的「大杂烩工具类」难以测试、难以替换。工具逻辑(纯计算、无副作用)用静态没问题,涉及状态和业务就别滥用。
  • 以为静态方法能被多态覆盖:子类写同名静态方法只是「隐藏」而非重写,调用哪个在编译期按引用类型就定了。多态那一章会看到实例方法的行为完全不同。

小结

static 成员属于类、被所有实例共享,用类名访问;静态方法没有 this、碰不到实例成员;static final 定义全局常量。下一节进入面向对象的第二根支柱:继承。